You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shenyu.apache.org by xi...@apache.org on 2023/02/09 03:48:13 UTC

[shenyu] branch master updated: Fixed jdk8 Map computeIfAbsent performance bug (#4338)

This is an automated email from the ASF dual-hosted git repository.

xiaoyu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git


The following commit(s) were added to refs/heads/master by this push:
     new 0a136faf6 Fixed jdk8 Map computeIfAbsent performance bug (#4338)
0a136faf6 is described below

commit 0a136faf622e16778dd004d7d5db6c791feeb1b6
Author: caojiajun <zj...@163.com>
AuthorDate: Thu Feb 9 11:48:07 2023 +0800

    Fixed jdk8 Map computeIfAbsent performance bug (#4338)
    
    * Fixed jdk8 Map computeIfAbsent performance bug
    
    * update code for checkstyle
    
    ---------
    
    Co-authored-by: hzcaojiajun <hz...@corp.netease.com>
    Co-authored-by: xiaoyu <xi...@apache.org>
---
 .../admin/service/impl/UpstreamCheckService.java      |  3 ++-
 .../admin/validation/validator/ExistedValidator.java  |  3 ++-
 .../java/org/apache/shenyu/common/utils/MapUtils.java | 19 +++++++++++++++++++
 .../loadbalancer/cache/UpstreamCacheManager.java      |  3 ++-
 .../shenyu/loadbalancer/cache/UpstreamCheckTask.java  |  3 ++-
 .../loadbalancer/spi/RoundRobinLoadBalancer.java      |  5 +++--
 .../plugin/base/cache/CommonPluginDataSubscriber.java |  3 ++-
 .../shenyu/plugin/base/cache/MatchDataCache.java      |  3 ++-
 .../shenyu/plugin/grpc/cache/GrpcClientCache.java     |  3 ++-
 .../nacos/NacosClientServerRegisterRepository.java    |  7 ++++---
 .../consul/ConsulInstanceRegisterRepository.java      |  3 ++-
 .../sync/data/nacos/handler/NacosCacheHandler.java    |  3 ++-
 12 files changed, 44 insertions(+), 14 deletions(-)

diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/UpstreamCheckService.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/UpstreamCheckService.java
index 4ecb0b5b5..55c91d155 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/UpstreamCheckService.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/UpstreamCheckService.java
@@ -47,6 +47,7 @@ import org.apache.shenyu.common.dto.convert.selector.ZombieUpstream;
 import org.apache.shenyu.common.enums.ConfigGroupEnum;
 import org.apache.shenyu.common.enums.DataEventTypeEnum;
 import org.apache.shenyu.common.enums.PluginEnum;
+import org.apache.shenyu.common.utils.MapUtils;
 import org.apache.shenyu.common.utils.UpstreamCheckUtils;
 import org.apache.shenyu.register.common.config.ShenyuRegisterCenterConfig;
 import org.slf4j.Logger;
@@ -184,7 +185,7 @@ public class UpstreamCheckService {
             return false;
         }
 
-        List<CommonUpstream> upstreams = UPSTREAM_MAP.computeIfAbsent(selectorId, k -> new CopyOnWriteArrayList<>());
+        List<CommonUpstream> upstreams = MapUtils.computeIfAbsent(UPSTREAM_MAP, selectorId, k -> new CopyOnWriteArrayList<>());
         if (commonUpstream.isStatus()) {
             Optional<CommonUpstream> exists = upstreams.stream().filter(item -> StringUtils.isNotBlank(item.getUpstreamUrl())
                     && item.getUpstreamUrl().equals(commonUpstream.getUpstreamUrl())).findFirst();
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/validation/validator/ExistedValidator.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/validation/validator/ExistedValidator.java
index b741a25bc..36abfa7aa 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/validation/validator/ExistedValidator.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/validation/validator/ExistedValidator.java
@@ -21,6 +21,7 @@ import org.apache.shenyu.admin.spring.SpringBeanUtils;
 import org.apache.shenyu.admin.utils.Assert;
 import org.apache.shenyu.admin.validation.ExistProvider;
 import org.apache.shenyu.admin.validation.annotation.Existed;
+import org.apache.shenyu.common.utils.MapUtils;
 import org.apache.shenyu.common.utils.ReflectUtils;
 
 import java.io.Serializable;
@@ -66,7 +67,7 @@ public class ExistedValidator implements ConstraintValidator<Existed, Serializab
     }
 
     private ExistProvider getExistProvider() {
-        return providerCacheMap.computeIfAbsent(annotation.provider().getName(), key -> SpringBeanUtils.getInstance().getBean(annotation.provider()));
+        return MapUtils.computeIfAbsent(providerCacheMap, annotation.provider().getName(), key -> SpringBeanUtils.getInstance().getBean(annotation.provider()));
     }
     
     private Boolean doValid(final Serializable value) {
diff --git a/shenyu-common/src/main/java/org/apache/shenyu/common/utils/MapUtils.java b/shenyu-common/src/main/java/org/apache/shenyu/common/utils/MapUtils.java
index b0801dd60..1c44c3f97 100644
--- a/shenyu-common/src/main/java/org/apache/shenyu/common/utils/MapUtils.java
+++ b/shenyu-common/src/main/java/org/apache/shenyu/common/utils/MapUtils.java
@@ -20,6 +20,7 @@ package org.apache.shenyu.common.utils;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 public class MapUtils {
@@ -35,4 +36,22 @@ public class MapUtils {
                 .map(m -> m.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> Objects.toString(e.getValue(), null))))
                 .orElse(null);
     }
+
+    /**
+     * This is jdk8 performance bug, see: https://bugs.openjdk.java.net/browse/JDK-8161372.
+     *
+     * @param map source map
+     * @param key key
+     * @param mappingFunction mappingFunction
+     * @param <K> k
+     * @param <V> v
+     * @return v
+     */
+    public static <K, V> V computeIfAbsent(final Map<K, V> map, final K key, final Function<? super K, ? extends V> mappingFunction) {
+        V v = map.get(key);
+        if (v != null) {
+            return v;
+        }
+        return map.computeIfAbsent(key, mappingFunction);
+    }
 }
diff --git a/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/cache/UpstreamCacheManager.java b/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/cache/UpstreamCacheManager.java
index 75854cf08..899ae24db 100644
--- a/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/cache/UpstreamCacheManager.java
+++ b/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/cache/UpstreamCacheManager.java
@@ -23,6 +23,7 @@ import org.apache.commons.collections4.CollectionUtils;
 import org.apache.shenyu.common.concurrent.ShenyuThreadFactory;
 import org.apache.shenyu.common.config.ShenyuConfig;
 import org.apache.shenyu.common.config.ShenyuConfig.UpstreamCheck;
+import org.apache.shenyu.common.utils.MapUtils;
 import org.apache.shenyu.common.utils.Singleton;
 import org.apache.shenyu.loadbalancer.entity.Upstream;
 
@@ -140,7 +141,7 @@ public final class UpstreamCacheManager {
     public void submit(final String selectorId, final List<Upstream> upstreamList) {
         List<Upstream> validUpstreamList = upstreamList.stream().filter(Upstream::isStatus).collect(Collectors.toList());
         if (CollectionUtils.isNotEmpty(validUpstreamList)) {
-            List<Upstream> existUpstream = UPSTREAM_MAP.computeIfAbsent(selectorId, k -> Lists.newArrayList());
+            List<Upstream> existUpstream = MapUtils.computeIfAbsent(UPSTREAM_MAP, selectorId, k -> Lists.newArrayList());
             existUpstream.stream().filter(upstream -> !validUpstreamList.contains(upstream))
                     .forEach(upstream -> task.triggerRemoveOne(selectorId, upstream));
             validUpstreamList.stream().filter(upstream -> !existUpstream.contains(upstream))
diff --git a/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/cache/UpstreamCheckTask.java b/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/cache/UpstreamCheckTask.java
index 856a5e6c1..46b9ddc76 100644
--- a/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/cache/UpstreamCheckTask.java
+++ b/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/cache/UpstreamCheckTask.java
@@ -22,6 +22,7 @@ import com.google.common.collect.Maps;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.shenyu.common.concurrent.ShenyuThreadFactory;
 import org.apache.shenyu.common.utils.GsonUtils;
+import org.apache.shenyu.common.utils.MapUtils;
 import org.apache.shenyu.common.utils.UpstreamCheckUtils;
 import org.apache.shenyu.loadbalancer.entity.Upstream;
 import org.slf4j.Logger;
@@ -251,7 +252,7 @@ public final class UpstreamCheckTask implements Runnable {
 
     private void putToMap(final Map<String, List<Upstream>> map, final String selectorId, final Upstream upstream) {
         synchronized (lock) {
-            List<Upstream> list = map.computeIfAbsent(selectorId, k -> Lists.newArrayList());
+            List<Upstream> list = MapUtils.computeIfAbsent(map, selectorId, k -> Lists.newArrayList());
             if (!list.contains(upstream)) {
                 list.add(upstream);
             }
diff --git a/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/spi/RoundRobinLoadBalancer.java b/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/spi/RoundRobinLoadBalancer.java
index d62160ab0..da3e62bec 100644
--- a/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/spi/RoundRobinLoadBalancer.java
+++ b/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/spi/RoundRobinLoadBalancer.java
@@ -17,6 +17,7 @@
 
 package org.apache.shenyu.loadbalancer.spi;
 
+import org.apache.shenyu.common.utils.MapUtils;
 import org.apache.shenyu.loadbalancer.entity.Upstream;
 import org.apache.shenyu.spi.Join;
 
@@ -42,7 +43,7 @@ public class RoundRobinLoadBalancer extends AbstractLoadBalancer {
     @Override
     public Upstream doSelect(final List<Upstream> upstreamList, final String ip) {
         String key = upstreamList.get(0).getUrl();
-        ConcurrentMap<String, WeightedRoundRobin> map = methodWeightMap.computeIfAbsent(key, k -> new ConcurrentHashMap<>(16));
+        ConcurrentMap<String, WeightedRoundRobin> map = MapUtils.computeIfAbsent(methodWeightMap, key, k -> new ConcurrentHashMap<>(16));
         int totalWeight = 0;
         long maxCurrent = Long.MIN_VALUE;
         long now = System.currentTimeMillis();
@@ -51,7 +52,7 @@ public class RoundRobinLoadBalancer extends AbstractLoadBalancer {
         for (Upstream upstream : upstreamList) {
             String rKey = upstream.getUrl();
             int weight = getWeight(upstream);
-            WeightedRoundRobin weightedRoundRobin = map.computeIfAbsent(rKey, k -> {
+            WeightedRoundRobin weightedRoundRobin = MapUtils.computeIfAbsent(map, rKey, k -> {
                 WeightedRoundRobin roundRobin = new WeightedRoundRobin();
                 roundRobin.setWeight(weight);
                 return roundRobin;
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/CommonPluginDataSubscriber.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/CommonPluginDataSubscriber.java
index 04e0a0240..408a3c432 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/CommonPluginDataSubscriber.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/CommonPluginDataSubscriber.java
@@ -24,6 +24,7 @@ import org.apache.shenyu.common.dto.SelectorData;
 import org.apache.shenyu.common.enums.DataEventTypeEnum;
 import org.apache.shenyu.common.enums.PluginHandlerEventEnum;
 import org.apache.shenyu.common.enums.RuleTrieEventEnum;
+import org.apache.shenyu.common.utils.MapUtils;
 import org.apache.shenyu.plugin.api.utils.SpringBeanUtils;
 import org.apache.shenyu.plugin.base.event.RuleTrieEvent;
 import org.apache.shenyu.plugin.base.handler.PluginDataHandler;
@@ -83,7 +84,7 @@ public class CommonPluginDataSubscriber implements PluginDataSubscriber {
         }
         for (PluginDataHandler handler : handlers) {
             String pluginNamed = handler.pluginNamed();
-            handlerMap.computeIfAbsent(pluginNamed, name -> {
+            MapUtils.computeIfAbsent(handlerMap, pluginNamed, name -> {
                 LOG.info("shenyu auto add extends plugin data handler name is :{}", pluginNamed);
                 return handler;
             });
diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/MatchDataCache.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/MatchDataCache.java
index 5b84b1e1a..e47a8709c 100644
--- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/MatchDataCache.java
+++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/MatchDataCache.java
@@ -21,6 +21,7 @@ import com.google.common.collect.Maps;
 import org.apache.shenyu.common.cache.MemorySafeWindowTinyLFUMap;
 import org.apache.shenyu.common.dto.RuleData;
 import org.apache.shenyu.common.dto.SelectorData;
+import org.apache.shenyu.common.utils.MapUtils;
 
 import java.util.Map;
 import java.util.Optional;
@@ -81,7 +82,7 @@ public final class MatchDataCache {
      * @param maxMemory    the max memory
      */
     public void cacheSelectorData(final String path, final SelectorData selectorData, final Integer maxMemory) {
-        SELECTOR_DATA_MAP.computeIfAbsent(selectorData.getPluginName(), map -> new MemorySafeWindowTinyLFUMap<>(maxMemory, 1 << 16)).put(path, selectorData);
+        MapUtils.computeIfAbsent(SELECTOR_DATA_MAP, selectorData.getPluginName(), map -> new MemorySafeWindowTinyLFUMap<>(maxMemory, 1 << 16)).put(path, selectorData);
     }
 
     /**
diff --git a/shenyu-plugin/shenyu-plugin-grpc/src/main/java/org/apache/shenyu/plugin/grpc/cache/GrpcClientCache.java b/shenyu-plugin/shenyu-plugin-grpc/src/main/java/org/apache/shenyu/plugin/grpc/cache/GrpcClientCache.java
index 7b9a1ba66..abc493993 100644
--- a/shenyu-plugin/shenyu-plugin-grpc/src/main/java/org/apache/shenyu/plugin/grpc/cache/GrpcClientCache.java
+++ b/shenyu-plugin/shenyu-plugin-grpc/src/main/java/org/apache/shenyu/plugin/grpc/cache/GrpcClientCache.java
@@ -18,6 +18,7 @@
 package org.apache.shenyu.plugin.grpc.cache;
 
 import com.google.common.collect.Maps;
+import org.apache.shenyu.common.utils.MapUtils;
 import org.apache.shenyu.plugin.grpc.client.GrpcClientBuilder;
 import org.apache.shenyu.plugin.grpc.client.ShenyuGrpcClient;
 
@@ -50,7 +51,7 @@ public final class GrpcClientCache {
      * @param contextPath contextPath
      */
     public static void initGrpcClient(final String contextPath) {
-        CLIENT_CACHE.computeIfAbsent(contextPath, s -> GrpcClientBuilder.buildClient(contextPath));
+        MapUtils.computeIfAbsent(CLIENT_CACHE, contextPath, s -> GrpcClientBuilder.buildClient(contextPath));
     }
     
     /**
diff --git a/shenyu-register-center/shenyu-register-client-server/shenyu-register-client-server-nacos/src/main/java/org/apache/shenyu/register/client/server/nacos/NacosClientServerRegisterRepository.java b/shenyu-register-center/shenyu-register-client-server/shenyu-register-client-server-nacos/src/main/java/org/apache/shenyu/register/client/server/nacos/NacosClientServerRegisterRepository.java
index d62283fef..242f55036 100644
--- a/shenyu-register-center/shenyu-register-client-server/shenyu-register-client-server-nacos/src/main/java/org/apache/shenyu/register/client/server/nacos/NacosClientServerRegisterRepository.java
+++ b/shenyu-register-center/shenyu-register-client-server/shenyu-register-client-server-nacos/src/main/java/org/apache/shenyu/register/client/server/nacos/NacosClientServerRegisterRepository.java
@@ -33,6 +33,7 @@ import org.apache.shenyu.common.constant.NacosPathConstants;
 import org.apache.shenyu.common.enums.RpcTypeEnum;
 import org.apache.shenyu.common.exception.ShenyuException;
 import org.apache.shenyu.common.utils.GsonUtils;
+import org.apache.shenyu.common.utils.MapUtils;
 import org.apache.shenyu.register.common.config.ShenyuRegisterCenterConfig;
 import org.apache.shenyu.register.common.dto.MetaDataRegisterDTO;
 import org.apache.shenyu.register.common.dto.URIRegisterDTO;
@@ -125,8 +126,8 @@ public class NacosClientServerRegisterRepository implements ShenyuClientServerRe
                 metadataConfigCache.add(serviceConfigName);
                 String metadata = healthyInstance.getMetadata().get("uriMetadata");
                 URIRegisterDTO uriRegisterDTO = GsonUtils.getInstance().fromJson(metadata, URIRegisterDTO.class);
-                services.computeIfAbsent(contextPath, k -> new ArrayList<>()).add(uriRegisterDTO);
-                uriServiceCache.computeIfAbsent(serviceName, k -> new ConcurrentSkipListSet<>()).add(contextPath);
+                MapUtils.computeIfAbsent(services, contextPath, k -> new ArrayList<>()).add(uriRegisterDTO);
+                MapUtils.computeIfAbsent(uriServiceCache, serviceName, k -> new ConcurrentSkipListSet<>()).add(contextPath);
             });
             if (RPC_URI_TYPE_SET.contains(rpcType)) {
                 services.values().forEach(this::publishRegisterURI);
@@ -137,7 +138,7 @@ public class NacosClientServerRegisterRepository implements ShenyuClientServerRe
                     List<Instance> instances = ((NamingEvent) event).getInstances();
                     instances.forEach(instance -> {
                         String contextPath = instance.getMetadata().get("contextPath");
-                        uriServiceCache.computeIfAbsent(serviceName, k -> new ConcurrentSkipListSet<>()).add(contextPath);
+                        MapUtils.computeIfAbsent(uriServiceCache, serviceName, k -> new ConcurrentSkipListSet<>()).add(contextPath);
                     });
                     refreshURIService(rpcType, serviceName);
                 }
diff --git a/shenyu-register-center/shenyu-register-instance/shenyu-register-instance-consul/src/main/java/org/apache/shenyu/register/instance/consul/ConsulInstanceRegisterRepository.java b/shenyu-register-center/shenyu-register-instance/shenyu-register-instance-consul/src/main/java/org/apache/shenyu/register/instance/consul/ConsulInstanceRegisterRepository.java
index a45ef4749..56b0539cd 100644
--- a/shenyu-register-center/shenyu-register-instance/shenyu-register-instance-consul/src/main/java/org/apache/shenyu/register/instance/consul/ConsulInstanceRegisterRepository.java
+++ b/shenyu-register-center/shenyu-register-instance/shenyu-register-instance-consul/src/main/java/org/apache/shenyu/register/instance/consul/ConsulInstanceRegisterRepository.java
@@ -29,6 +29,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.shenyu.common.concurrent.ShenyuThreadFactory;
 import org.apache.shenyu.common.constant.Constants;
 import org.apache.shenyu.common.utils.GsonUtils;
+import org.apache.shenyu.common.utils.MapUtils;
 import org.apache.shenyu.register.instance.api.ShenyuInstanceRegisterRepository;
 import org.apache.shenyu.register.instance.api.config.RegisterConfig;
 import org.apache.shenyu.register.instance.api.entity.InstanceEntity;
@@ -168,7 +169,7 @@ public class ConsulInstanceRegisterRepository implements ShenyuInstanceRegisterR
             return;
         }
         synchronized (lock) {
-            eventListeners = listenerMap.computeIfAbsent(selectKey, s -> new HashSet<>());
+            eventListeners = MapUtils.computeIfAbsent(listenerMap, selectKey, s -> new HashSet<>());
         }
         eventListeners.add(watcherListener);
         watchFutures.add(this.executor.scheduleWithFixedDelay(() -> this.watchConfigKeyValues(selectKey),
diff --git a/shenyu-sync-data-center/shenyu-sync-data-nacos/src/main/java/org/apache/shenyu/sync/data/nacos/handler/NacosCacheHandler.java b/shenyu-sync-data-center/shenyu-sync-data-nacos/src/main/java/org/apache/shenyu/sync/data/nacos/handler/NacosCacheHandler.java
index e924ce94d..87e3f6462 100644
--- a/shenyu-sync-data-center/shenyu-sync-data-nacos/src/main/java/org/apache/shenyu/sync/data/nacos/handler/NacosCacheHandler.java
+++ b/shenyu-sync-data-center/shenyu-sync-data-nacos/src/main/java/org/apache/shenyu/sync/data/nacos/handler/NacosCacheHandler.java
@@ -29,6 +29,7 @@ import org.apache.shenyu.common.dto.PluginData;
 import org.apache.shenyu.common.dto.RuleData;
 import org.apache.shenyu.common.dto.SelectorData;
 import org.apache.shenyu.common.utils.GsonUtils;
+import org.apache.shenyu.common.utils.MapUtils;
 import org.apache.shenyu.sync.data.api.AuthDataSubscriber;
 import org.apache.shenyu.sync.data.api.MetaDataSubscriber;
 import org.apache.shenyu.sync.data.api.PluginDataSubscriber;
@@ -171,7 +172,7 @@ public class NacosCacheHandler {
             }
         };
         oc.change(getConfigAndSignListener(dataId, listener));
-        LISTENERS.computeIfAbsent(dataId, key -> new ArrayList<>()).add(listener);
+        MapUtils.computeIfAbsent(LISTENERS, dataId, key -> new ArrayList<>()).add(listener);
     }
 
     protected interface OnChange {