You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by al...@apache.org on 2021/11/01 11:00:38 UTC
[dubbo] branch 3.0 updated: Fix MD5Utils concurrent error (#9176)
This is an automated email from the ASF dual-hosted git repository.
albumenj pushed a commit to branch 3.0
in repository https://gitbox.apache.org/repos/asf/dubbo.git
The following commit(s) were added to refs/heads/3.0 by this push:
new 68381ba Fix MD5Utils concurrent error (#9176)
68381ba is described below
commit 68381ba7662fb65d68a38a7f966123714808f110
Author: Gong Dewei <ky...@qq.com>
AuthorDate: Mon Nov 1 19:00:06 2021 +0800
Fix MD5Utils concurrent error (#9176)
---
.../org/apache/dubbo/common/utils/MD5Utils.java | 19 +++--
.../apache/dubbo/common/utils/MD5UtilsTest.java | 95 ++++++++++++++++++++++
.../support/nacos/NacosDynamicConfiguration.java | 4 +-
.../apache/dubbo/metadata/RevisionResolver.java | 4 +-
.../metadata/store/nacos/NacosMetadataReport.java | 14 ++--
5 files changed, 121 insertions(+), 15 deletions(-)
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/MD5Utils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/MD5Utils.java
index 92b520d..2d48631 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/MD5Utils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/MD5Utils.java
@@ -36,9 +36,9 @@ public class MD5Utils {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};
- private static MessageDigest mdInst;
+ private MessageDigest mdInst;
- static {
+ public MD5Utils() {
try {
mdInst = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
@@ -46,9 +46,17 @@ public class MD5Utils {
}
}
- public static String getMd5(String value) {
- mdInst.update(value.getBytes(UTF_8));
- byte[] md5 = mdInst.digest();
+ /**
+ * Calculation md5 value of specify string
+ * @param input
+ */
+ public String getMd5(String input) {
+ byte[] md5;
+ // MessageDigest instance is NOT thread-safe
+ synchronized (mdInst) {
+ mdInst.update(input.getBytes(UTF_8));
+ md5 = mdInst.digest();
+ }
int j = md5.length;
char str[] = new char[j * 2];
@@ -61,5 +69,4 @@ public class MD5Utils {
return new String(str);
}
-
}
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/MD5UtilsTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/MD5UtilsTest.java
new file mode 100644
index 0000000..4a5ca05
--- /dev/null
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/MD5UtilsTest.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.utils;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class MD5UtilsTest {
+
+ @Test
+ public void test() {
+ MD5Utils sharedMd5Utils = new MD5Utils();
+ final String[] input = {"provider-appgroup-one/org.apache.dubbo.config.spring.api.HelloService:dubboorg.apache.dubbo.config.spring.api.HelloService{REGISTRY_CLUSTER=registry-one, anyhost=true, application=provider-app, background=false, compiler=javassist, deprecated=false, dubbo=2.0.2, dynamic=true, file.cache=false, generic=false, group=group-one, interface=org.apache.dubbo.config.spring.api.HelloService, logger=slf4j, metadata-type=remote, methods=sayHello, organization=test, [...]
+ "provider-appgroup-two/org.apache.dubbo.config.spring.api.DemoService:dubboorg.apache.dubbo.config.spring.api.DemoService{REGISTRY_CLUSTER=registry-two, anyhost=true, application=provider-app, background=false, compiler=javassist, deprecated=false, dubbo=2.0.2, dynamic=true, file.cache=false, generic=false, group=group-two, interface=org.apache.dubbo.config.spring.api.DemoService, logger=slf4j, metadata-type=remote, methods=sayName,getBox, organization=test, owner=com.test, r [...]
+ final String[] result = {sharedMd5Utils.getMd5(input[0]), new MD5Utils().getMd5(input[1])};
+
+ System.out.println("Expected result: " + Arrays.asList(result));
+ int nThreads = 8;
+ CountDownLatch latch = new CountDownLatch(nThreads);
+ List<Throwable> errors = Collections.synchronizedList(new ArrayList<>());
+ ExecutorService executorService = Executors.newFixedThreadPool(nThreads);
+ try {
+
+ for (int i = 0; i < nThreads; i++) {
+ MD5Utils md5Utils = i < nThreads / 2 ? sharedMd5Utils : new MD5Utils();
+ executorService.submit(new Md5Task(input[i % 2], result[i % 2], md5Utils, latch, errors));
+ }
+ latch.await();
+ Assertions.assertEquals(Collections.EMPTY_LIST, errors);
+ Assertions.assertEquals(0, latch.getCount());
+ } catch (Throwable e) {
+ Assertions.fail(StringUtils.toString(e));
+ } finally {
+ executorService.shutdown();
+ }
+ }
+
+ static class Md5Task implements Runnable {
+
+ private final String input;
+ private final String expected;
+ private final MD5Utils md5Utils;
+ private final CountDownLatch latch;
+ private final List<Throwable> errorCollector;
+
+ public Md5Task(String input, String expected, MD5Utils md5Utils, CountDownLatch latch, List<Throwable> errorCollector) {
+ this.input = input;
+ this.expected = expected;
+ this.md5Utils = md5Utils;
+ this.latch = latch;
+ this.errorCollector = errorCollector;
+ }
+
+ @Override
+ public void run() {
+ int i = 0;
+ long start = System.currentTimeMillis();
+ try {
+ for (; i < 200; i++) {
+ Assertions.assertEquals(expected, md5Utils.getMd5(input));
+ md5Utils.getMd5("test#" + i);
+ }
+ } catch (Throwable e) {
+ errorCollector.add(e);
+ e.printStackTrace();
+ } finally {
+ long cost = System.currentTimeMillis() - start;
+ System.out.println("[" + Thread.currentThread().getName() + "] progress: " + i + ", cost: " + cost);
+ latch.countDown();
+ }
+ }
+ }
+}
diff --git a/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java b/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java
index 83a0fac..7d35543 100644
--- a/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java
+++ b/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java
@@ -85,6 +85,8 @@ public class NacosDynamicConfiguration implements DynamicConfiguration {
*/
private final Map<String, NacosConfigListener> watchListenerMap;
+ private MD5Utils md5Utils = new MD5Utils();
+
NacosDynamicConfiguration(URL url) {
this.nacosProperties = buildNacosProperties(url);
this.configService = buildConfigService(url);
@@ -221,7 +223,7 @@ public class NacosDynamicConfiguration implements DynamicConfiguration {
String content = getConfig(key, group);
String casMd5 = "";
if (StringUtils.isNotEmpty(content)) {
- casMd5 = MD5Utils.getMd5(content);
+ casMd5 = md5Utils.getMd5(content);
}
return new ConfigItem(content, casMd5);
}
diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/RevisionResolver.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/RevisionResolver.java
index 155295c..a1c9e19 100644
--- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/RevisionResolver.java
+++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/RevisionResolver.java
@@ -23,8 +23,10 @@ public class RevisionResolver {
public static final String EMPTY_REVISION = "0";
+ private static MD5Utils md5Utils = new MD5Utils();
+
public static String calRevision(String metadata) {
- return MD5Utils.getMd5(metadata);
+ return md5Utils.getMd5(metadata);
}
}
diff --git a/dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReport.java b/dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReport.java
index 30b26b7..23e866a 100644
--- a/dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReport.java
+++ b/dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReport.java
@@ -17,6 +17,11 @@
package org.apache.dubbo.metadata.store.nacos;
+import com.alibaba.nacos.api.NacosFactory;
+import com.alibaba.nacos.api.PropertyKeyConst;
+import com.alibaba.nacos.api.config.listener.AbstractSharedListener;
+import com.alibaba.nacos.api.exception.NacosException;
+import com.google.gson.Gson;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.config.configcenter.ConfigChangeType;
import org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;
@@ -36,12 +41,6 @@ import org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier;
import org.apache.dubbo.metadata.report.support.AbstractMetadataReport;
import org.apache.dubbo.rpc.RpcException;
-import com.alibaba.nacos.api.NacosFactory;
-import com.alibaba.nacos.api.PropertyKeyConst;
-import com.alibaba.nacos.api.config.listener.AbstractSharedListener;
-import com.alibaba.nacos.api.exception.NacosException;
-import com.google.gson.Gson;
-
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -80,6 +79,7 @@ public class NacosMetadataReport extends AbstractMetadataReport {
private Map<String, MappingDataListener> casListenerMap = new ConcurrentHashMap<>();
+ private MD5Utils md5Utils = new MD5Utils();
public NacosMetadataReport(URL url) {
super(url);
@@ -226,7 +226,7 @@ public class NacosMetadataReport extends AbstractMetadataReport {
String content = getConfig(key, group);
String casMd5 = "";
if (StringUtils.isNotEmpty(content)) {
- casMd5 = MD5Utils.getMd5(content);
+ casMd5 = md5Utils.getMd5(content);
}
return new ConfigItem(content, casMd5);
}