From 4ee91d865034f280f376497c23adca0d17caabc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=B1=E6=81=92?= Date: Wed, 7 Sep 2022 21:13:22 +0800 Subject: [PATCH 1/3] improve efficiency of list difference --- .../client/AllConnectConnectionHolder.java | 6 +- core/api/pom.xml | 10 ++ .../CollectionDifferenceBenchMarkTest.java | 125 ++++++++++++++++++ .../sofa/rpc/common/struct/SetDifference.java | 103 +++++++++++++++ .../rpc/common/struct/SetDifferenceTest.java | 77 +++++++++++ pom.xml | 14 ++ 6 files changed, 332 insertions(+), 3 deletions(-) create mode 100644 core/api/src/test/java/com/alipay/sofa/rpc/bench/CollectionDifferenceBenchMarkTest.java create mode 100644 core/common/src/main/java/com/alipay/sofa/rpc/common/struct/SetDifference.java create mode 100644 core/common/src/test/java/com/alipay/sofa/rpc/common/struct/SetDifferenceTest.java diff --git a/core-impl/client/src/main/java/com/alipay/sofa/rpc/client/AllConnectConnectionHolder.java b/core-impl/client/src/main/java/com/alipay/sofa/rpc/client/AllConnectConnectionHolder.java index 51305292e..8f9a2522b 100644 --- a/core-impl/client/src/main/java/com/alipay/sofa/rpc/client/AllConnectConnectionHolder.java +++ b/core-impl/client/src/main/java/com/alipay/sofa/rpc/client/AllConnectConnectionHolder.java @@ -21,9 +21,9 @@ import com.alipay.sofa.rpc.common.RpcConstants; import com.alipay.sofa.rpc.common.RpcOptions; import com.alipay.sofa.rpc.common.struct.ConcurrentHashSet; -import com.alipay.sofa.rpc.common.struct.ListDifference; import com.alipay.sofa.rpc.common.struct.NamedThreadFactory; import com.alipay.sofa.rpc.common.struct.ScheduledService; +import com.alipay.sofa.rpc.common.struct.SetDifference; import com.alipay.sofa.rpc.common.utils.CommonUtils; import com.alipay.sofa.rpc.common.utils.ExceptionUtils; import com.alipay.sofa.rpc.common.utils.NetUtils; @@ -379,10 +379,10 @@ public void updateProviders(ProviderGroup providerGroup) { } else { Collection nowall = currentProviderList(); List oldAllP = providerGroup.getProviderInfos(); - List nowAllP = new ArrayList(nowall);// 当前全部 + Set nowAllP = new HashSet(nowall);// 当前全部 // 比较当前的和最新的 - ListDifference diff = new ListDifference(oldAllP, nowAllP); + SetDifference diff = new SetDifference(new HashSet<>(oldAllP), nowAllP); List needAdd = diff.getOnlyOnLeft(); // 需要新建 List needDelete = diff.getOnlyOnRight(); // 需要删掉 if (!needAdd.isEmpty()) { diff --git a/core/api/pom.xml b/core/api/pom.xml index 34e851ad1..24917620a 100644 --- a/core/api/pom.xml +++ b/core/api/pom.xml @@ -27,6 +27,16 @@ com.alibaba transmittable-thread-local + + org.openjdk.jmh + jmh-core + test + + + org.openjdk.jmh + jmh-generator-annprocess + test + diff --git a/core/api/src/test/java/com/alipay/sofa/rpc/bench/CollectionDifferenceBenchMarkTest.java b/core/api/src/test/java/com/alipay/sofa/rpc/bench/CollectionDifferenceBenchMarkTest.java new file mode 100644 index 000000000..c15284b04 --- /dev/null +++ b/core/api/src/test/java/com/alipay/sofa/rpc/bench/CollectionDifferenceBenchMarkTest.java @@ -0,0 +1,125 @@ +/** + * Alipay.com Inc. + * Copyright (c) 2004-2022 All Rights Reserved. + */ +package com.alipay.sofa.rpc.bench; + +import com.alipay.sofa.rpc.client.ProviderHelper; +import com.alipay.sofa.rpc.client.ProviderInfo; +import com.alipay.sofa.rpc.common.struct.ListDifference; +import com.alipay.sofa.rpc.common.struct.SetDifference; +import org.junit.Assert; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.profile.GCProfiler; +import org.openjdk.jmh.results.format.ResultFormatType; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +/** + * + * @author xiaojian.xj + * @version : CollectionDifferenceBenchMarkTest.java, v 0.1 2022年09月06日 21:45 xiaojian.xj Exp $ + */ +@BenchmarkMode(Mode.AverageTime) +@Warmup(iterations = 3, time = 1) +@Measurement(iterations = 3, time = 1) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Fork(5) +@Threads(1) +@State(value = Scope.Benchmark) +public class CollectionDifferenceBenchMarkTest { + + private static final String URL_PATTERN = "%s:12200?rpcVer=50803&serialization=hessian2&weight=100&timeout=3000&appName=testApp&p=1&v=4.0&_SERIALIZETYPE=hessian2&_WEIGHT=100&_TIMEOUT=3000&app_name=testApp"; + + private static final List EXIST = new ArrayList<>(); + + private static final List UPDATE = new ArrayList<>(); + + private static Set EXIST_SET; + + private static Set UPDATE_SET; + + private static final String TO_BE_ADD = String.format(URL_PATTERN, getRandomIp()); + + private static final String TO_BE_REMOVE = String.format(URL_PATTERN, getRandomIp()); + + @Param(value = {"1000", "5000", "10000", "20000", "50000"}) + private int LENGTH; + + public static void main(String[] args) throws RunnerException { + Options opt = new OptionsBuilder() + .include(CollectionDifferenceBenchMarkTest.class.getSimpleName()) + .addProfiler(GCProfiler.class) + .result("result.json") + .resultFormat(ResultFormatType.JSON).build(); + new Runner(opt).run(); + } + + @Benchmark + public void testListDifference() { + ListDifference difference = new ListDifference(EXIST, UPDATE); + Assert.assertEquals(difference.getOnBoth().size(), LENGTH); + Assert.assertEquals(difference.getOnlyOnLeft().size(), 1); + Assert.assertEquals(difference.getOnlyOnRight().size(), 1); + } + + @Benchmark + public void testSetDifference() { + SetDifference difference = new SetDifference(EXIST_SET, UPDATE_SET); + Assert.assertEquals(difference.getOnBoth().size(), LENGTH); + Assert.assertEquals(difference.getOnlyOnLeft().size(), 1); + Assert.assertEquals(difference.getOnlyOnRight().size(), 1); + } + + @Setup + public void prepareData() { + Set existUrl = new HashSet<>(); + for (int i = 0; i < LENGTH; i++) { + String url = String.format(URL_PATTERN, getRandomIp());; + + while (existUrl.contains(url)) { + url = String.format(URL_PATTERN, getRandomIp()); + } + existUrl.add(url); + EXIST.add(ProviderHelper.toProviderInfo(url)); + UPDATE.add(ProviderHelper.toProviderInfo(url)); + } + EXIST.add(ProviderHelper.toProviderInfo(TO_BE_REMOVE)); + UPDATE.add(ProviderHelper.toProviderInfo(TO_BE_ADD)); + + EXIST_SET = new HashSet<>(EXIST); + UPDATE_SET = new HashSet<>(UPDATE); + } + + @TearDown + public void clean() { + EXIST.clear(); + UPDATE.clear(); + } + + public static String getRandomIp() { + Random r = new Random(); + return r.nextInt(256) + "." + r.nextInt(256) + "." + r.nextInt(256) + "." + r.nextInt(256); + } +} diff --git a/core/common/src/main/java/com/alipay/sofa/rpc/common/struct/SetDifference.java b/core/common/src/main/java/com/alipay/sofa/rpc/common/struct/SetDifference.java new file mode 100644 index 000000000..1bf7407df --- /dev/null +++ b/core/common/src/main/java/com/alipay/sofa/rpc/common/struct/SetDifference.java @@ -0,0 +1,103 @@ +/** + * Alipay.com Inc. + * Copyright (c) 2004-2022 All Rights Reserved. + */ +package com.alipay.sofa.rpc.common.struct; + +import com.alipay.sofa.rpc.common.utils.CommonUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +/** + * + * 比较两个set的不同,列出差异部分:包括左侧独有,右侧独有,双方都有 + * @author xiaojian.xj + * @version : SetDifference.java, v 0.1 2022年09月07日 15:39 xiaojian.xj Exp $ + */ +public class SetDifference { + + /** + * The Only on left. + */ + private List onlyOnLeft; + + /** + * The Only on right. + */ + private List onlyOnRight; + + /** + * The On both. + */ + private List onBoth; + + public SetDifference(Set left, Set right) { + if (CommonUtils.isEmpty(left) || CommonUtils.isEmpty(right)) { + this.onlyOnLeft = Collections.unmodifiableList(left == null ? new ArrayList() : new ArrayList(left)); + this.onlyOnRight = Collections.unmodifiableList(right == null ? new ArrayList() : new ArrayList(right)); + this.onBoth = Collections.unmodifiableList(new ArrayList()); + return; + } + + List onlyOnLeft = new ArrayList<>(left.size()); + List onlyOnRight = new ArrayList(right.size()); + List onBoth = new ArrayList(left.size()); + + for (T leftValue : left) { + if (right.contains(leftValue)) { + onBoth.add(leftValue); + } else { + onlyOnLeft.add(leftValue); + } + } + + for (T rightValue : right) { + if (!left.contains(rightValue)) { + onlyOnRight.add(rightValue); + } + } + + this.onlyOnLeft = Collections.unmodifiableList(onlyOnLeft); + this.onlyOnRight = Collections.unmodifiableList(onlyOnRight); + this.onBoth = Collections.unmodifiableList(onBoth); + } + + /** + * Are equal. + * + * @return the boolean + */ + public boolean areEqual() { + return onlyOnLeft.isEmpty() && onlyOnRight.isEmpty(); + } + + /** + * Gets only on left. + * + * @return the only on left + */ + public List getOnlyOnLeft() { + return onlyOnLeft; + } + + /** + * Gets only on right. + * + * @return the only on right + */ + public List getOnlyOnRight() { + return onlyOnRight; + } + + /** + * Gets on both. + * + * @return the on both + */ + public List getOnBoth() { + return onBoth; + } +} diff --git a/core/common/src/test/java/com/alipay/sofa/rpc/common/struct/SetDifferenceTest.java b/core/common/src/test/java/com/alipay/sofa/rpc/common/struct/SetDifferenceTest.java new file mode 100644 index 000000000..cc466d796 --- /dev/null +++ b/core/common/src/test/java/com/alipay/sofa/rpc/common/struct/SetDifferenceTest.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 com.alipay.sofa.rpc.common.struct; + +import org.junit.Assert; +import org.junit.Test; +import org.mockito.internal.util.collections.Sets; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class SetDifferenceTest { + + @Test + public void testDifference() throws Exception { + Set s1 = Sets.newSet("111", "222", "333"); + Set s2 = Sets.newSet("111", "333", "444", "555", "666"); + + SetDifference difference = new SetDifference(s1, s2); + Assert.assertFalse(difference.areEqual()); + + List add = difference.getOnlyOnRight(); + List removed = difference.getOnlyOnLeft(); + List same = difference.getOnBoth(); + + Assert.assertEquals(add.size(), 3); + Assert.assertEquals(removed.size(), 1); + Assert.assertEquals(same.size(), 2); + + Assert.assertEquals(add.get(0), "444"); + Assert.assertEquals(removed.get(0), "222"); + + s1 = Sets.newSet("111", "222", "333"); + s2 = Sets.newSet("111", "333", "222"); + + difference = new SetDifference(s1, s2); + Assert.assertTrue(difference.areEqual()); + + add = difference.getOnlyOnRight(); + removed = difference.getOnlyOnLeft(); + same = difference.getOnBoth(); + + Assert.assertEquals(add.size(), 0); + Assert.assertEquals(removed.size(), 0); + Assert.assertEquals(same.size(), 3); + + s1 = new HashSet<>(); + s2 = Sets.newSet(); + difference = new SetDifference(s1, s2); + Assert.assertTrue(difference.areEqual()); + + s1 = null; + s2 = Sets.newSet(); + difference = new SetDifference(s1, s2); + Assert.assertTrue(difference.areEqual()); + + s1 = Collections.emptySet(); + s2 = null; + difference = new SetDifference(s1, s2); + Assert.assertTrue(difference.areEqual()); + } +} diff --git a/pom.xml b/pom.xml index 00f38da67..e16648e35 100644 --- a/pom.xml +++ b/pom.xml @@ -60,11 +60,25 @@ mockito-core test + + + org.openjdk.jmh + jmh-core + ${jmh.version} + test + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} + test + 5.8.7 + 1.33 true true true From 46305d61e4ed9529e2c2b74c418f27969d49f442 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=B1=E6=81=92?= Date: Tue, 13 Sep 2022 10:05:13 +0800 Subject: [PATCH 2/3] improve efficiency of list difference --- core/api/pom.xml | 10 ---------- .../rpc/bench/CollectionDifferenceBenchMarkTest.java | 2 +- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/core/api/pom.xml b/core/api/pom.xml index 24917620a..34e851ad1 100644 --- a/core/api/pom.xml +++ b/core/api/pom.xml @@ -27,16 +27,6 @@ com.alibaba transmittable-thread-local - - org.openjdk.jmh - jmh-core - test - - - org.openjdk.jmh - jmh-generator-annprocess - test - diff --git a/core/api/src/test/java/com/alipay/sofa/rpc/bench/CollectionDifferenceBenchMarkTest.java b/core/api/src/test/java/com/alipay/sofa/rpc/bench/CollectionDifferenceBenchMarkTest.java index c15284b04..d50b61865 100644 --- a/core/api/src/test/java/com/alipay/sofa/rpc/bench/CollectionDifferenceBenchMarkTest.java +++ b/core/api/src/test/java/com/alipay/sofa/rpc/bench/CollectionDifferenceBenchMarkTest.java @@ -64,7 +64,7 @@ public class CollectionDifferenceBenchMarkTest { private static final String TO_BE_REMOVE = String.format(URL_PATTERN, getRandomIp()); - @Param(value = {"1000", "5000", "10000", "20000", "50000"}) + @Param(value = {"1000", "5000", "10000", "20000"}) private int LENGTH; public static void main(String[] args) throws RunnerException { From e26141f6b626633e85d380bd77dc9d1aa90a1ebe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=B1=E6=81=92?= Date: Tue, 13 Sep 2022 10:22:26 +0800 Subject: [PATCH 3/3] format code --- .../CollectionDifferenceBenchMarkTest.java | 18 +++++++++++++++--- .../sofa/rpc/common/struct/SetDifference.java | 18 +++++++++++++++--- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/core/api/src/test/java/com/alipay/sofa/rpc/bench/CollectionDifferenceBenchMarkTest.java b/core/api/src/test/java/com/alipay/sofa/rpc/bench/CollectionDifferenceBenchMarkTest.java index d50b61865..2d2dd2bd7 100644 --- a/core/api/src/test/java/com/alipay/sofa/rpc/bench/CollectionDifferenceBenchMarkTest.java +++ b/core/api/src/test/java/com/alipay/sofa/rpc/bench/CollectionDifferenceBenchMarkTest.java @@ -1,6 +1,18 @@ -/** - * Alipay.com Inc. - * Copyright (c) 2004-2022 All Rights Reserved. +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.alipay.sofa.rpc.bench; diff --git a/core/common/src/main/java/com/alipay/sofa/rpc/common/struct/SetDifference.java b/core/common/src/main/java/com/alipay/sofa/rpc/common/struct/SetDifference.java index 1bf7407df..dad969561 100644 --- a/core/common/src/main/java/com/alipay/sofa/rpc/common/struct/SetDifference.java +++ b/core/common/src/main/java/com/alipay/sofa/rpc/common/struct/SetDifference.java @@ -1,6 +1,18 @@ -/** - * Alipay.com Inc. - * Copyright (c) 2004-2022 All Rights Reserved. +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.alipay.sofa.rpc.common.struct;