From 1f125c4af34eeec962f91eaf5f52cf487cf43e8a Mon Sep 17 00:00:00 2001 From: Andy Date: Fri, 29 Mar 2019 22:18:53 +0800 Subject: [PATCH] Fix the issue: ArrayIndexOutOfBoundsException may be thrown when invokes taskDispatcher.addTask --- .../ephemeral/distro/TaskDispatcher.java | 11 +---- .../nacos/naming/misc/UtilsAndCommons.java | 30 +++++++++++++ .../ephemeral/distro/TaskDispatcherTest.java | 44 +++++++++++++++++++ 3 files changed, 76 insertions(+), 9 deletions(-) create mode 100644 naming/src/test/java/com/alibaba/nacos/naming/consistency/ephemeral/distro/TaskDispatcherTest.java diff --git a/naming/src/main/java/com/alibaba/nacos/naming/consistency/ephemeral/distro/TaskDispatcher.java b/naming/src/main/java/com/alibaba/nacos/naming/consistency/ephemeral/distro/TaskDispatcher.java index 727932dcd..97d03edc8 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/consistency/ephemeral/distro/TaskDispatcher.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/consistency/ephemeral/distro/TaskDispatcher.java @@ -17,10 +17,7 @@ package com.alibaba.nacos.naming.consistency.ephemeral.distro; import com.alibaba.fastjson.JSON; import com.alibaba.nacos.naming.cluster.servers.Server; -import com.alibaba.nacos.naming.misc.GlobalConfig; -import com.alibaba.nacos.naming.misc.GlobalExecutor; -import com.alibaba.nacos.naming.misc.Loggers; -import com.alibaba.nacos.naming.misc.NetUtils; +import com.alibaba.nacos.naming.misc.*; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -58,12 +55,8 @@ public class TaskDispatcher { } } - public int mapTask(String key) { - return Math.abs(key.hashCode()) % partitionConfig.getTaskDispatchThreadCount(); - } - public void addTask(String key) { - taskSchedulerList.get(mapTask(key)).addTask(key); + taskSchedulerList.get(UtilsAndCommons.shakeUp(key, partitionConfig.getTaskDispatchThreadCount())).addTask(key); } public class TaskScheduler implements Runnable { diff --git a/naming/src/main/java/com/alibaba/nacos/naming/misc/UtilsAndCommons.java b/naming/src/main/java/com/alibaba/nacos/naming/misc/UtilsAndCommons.java index 0891ae2b4..d3c8a2804 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/misc/UtilsAndCommons.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/misc/UtilsAndCommons.java @@ -237,4 +237,34 @@ public class UtilsAndCommons { public static String assembleFullServiceName(String namespaceId, String serviceName) { return namespaceId + UtilsAndCommons.NAMESPACE_SERVICE_CONNECTOR + serviceName; } + + /** + * 根据指定的字符串计算出一个0(含)到{@code upperLimit}(不含)之间的数字,本方法会试图让不同的字符串较均匀的分布在0到{@code upperLimit}之间。 + * (Provide a number between 0(include) and {@code upperLimit}(exclude) for the given {@code string}, the number will be nearly uniform distribution.) + *

+ *

+ * 举个例子:假设有N个提供相同服务的服务器地址被存在一个数组中,为了实现负载均衡,可以根据调用者的名字决定使用哪个服务器。 + * (e.g. Assume there's an array which contains some IP of the servers provide the same service, the caller name can be used to choose the server to achieve load balance.) + *

+     *     String[] serverIps = new String[10];
+     *     int index = shakeUp("callerName", serverIps.length);
+     *     String targetServerIp = serverIps[index];
+     * 
+ * + * @param string 字符串。如果为null会固定返回0 (a string. the number 0 will be returned if it's null) + * @param upperLimit 返回值的上限,必须为正整数(>0) (the upper limit of the returned number, must be a positive integer, which means > 0) + * @return 0(含)到upperLimit(不含)之间的一个数字 (a number between 0(include) and upperLimit(exclude)) + * @throws IllegalArgumentException if the upper limit equals or less than 0 + * @since 1.0.0 + */ + public static int shakeUp(String string, int upperLimit) { + if (upperLimit < 1) { + throw new IllegalArgumentException("upper limit must be greater than 0"); + } + if (string == null) { + return 0; + } + return (string.hashCode() & Integer.MAX_VALUE) % upperLimit; + } + } diff --git a/naming/src/test/java/com/alibaba/nacos/naming/consistency/ephemeral/distro/TaskDispatcherTest.java b/naming/src/test/java/com/alibaba/nacos/naming/consistency/ephemeral/distro/TaskDispatcherTest.java new file mode 100644 index 000000000..6a67f9430 --- /dev/null +++ b/naming/src/test/java/com/alibaba/nacos/naming/consistency/ephemeral/distro/TaskDispatcherTest.java @@ -0,0 +1,44 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.nacos.naming.consistency.ephemeral.distro; + +import com.alibaba.nacos.naming.misc.GlobalConfig; +import org.junit.Before; +import org.junit.Test; +import org.springframework.test.util.ReflectionTestUtils; + +/** + * @author jifengnan + */ +public class TaskDispatcherTest { + + private TaskDispatcher taskDispatcher; + + @Before + public void init() { + taskDispatcher = new TaskDispatcher(); + GlobalConfig conf = new GlobalConfig(); + ReflectionTestUtils.setField(conf, "taskDispatchThreadCount", 3); + ReflectionTestUtils.setField(taskDispatcher, "partitionConfig", conf); + taskDispatcher.init(); + } + + @Test + public void testAddTask() { + char[] chars = new char[]{2325, 9, 30, 12, 2}; + taskDispatcher.addTask(new String(chars)); + } +}