From 10c23300e18b66ea2a7d56f10aafb13d7138c54b Mon Sep 17 00:00:00 2001 From: Violeta Georgieva Date: Wed, 22 Mar 2023 21:12:53 +0200 Subject: [PATCH] Ensure correct initial capacity is used for the map (#2739) --- .../reactor/netty/internal/util/MapUtils.java | 23 ++++++++++++++++--- .../java/reactor/netty/tcp/TcpServerBind.java | 5 ++-- .../netty/transport/ServerTransport.java | 2 +- .../netty/transport/TransportConfig.java | 3 ++- .../netty/http/server/HttpPredicate.java | 5 ++-- .../netty/http/server/HttpServerBind.java | 5 ++-- 6 files changed, 32 insertions(+), 11 deletions(-) diff --git a/reactor-netty-core/src/main/java/reactor/netty/internal/util/MapUtils.java b/reactor-netty-core/src/main/java/reactor/netty/internal/util/MapUtils.java index 1e3e8aaa08..ad20dc3bad 100644 --- a/reactor-netty-core/src/main/java/reactor/netty/internal/util/MapUtils.java +++ b/reactor-netty-core/src/main/java/reactor/netty/internal/util/MapUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 VMware, Inc. or its affiliates, All Rights Reserved. + * Copyright (c) 2022-2023 VMware, Inc. or its affiliates, All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,8 +19,7 @@ import java.util.function.Function; /** - * It's a temporary workaround for Java 8 specific performance issue JDK-8161372 - * and this class should be removed once the Java 8 support is dropped. + * This class contains temporary workarounds for Java 8 {@link Map} issues. *

Note: This utility class is for internal use only. It can be removed at any time. * * @author zimatars @@ -29,6 +28,24 @@ public final class MapUtils { /** + * This is a temporary workaround for Java 8 issue https://bugs.openjdk.org/browse/JDK-8186958. Fix is available + * in Java 19. + *

+ * Calculate the initial capacity for the {@link Map} from the expected size and the default load factor + * for the {@link Map} (0.75). + * + * @param expectedSize the expected size + * @return the initial capacity for the {@link Map} + * @since 1.0.31 + */ + public static int calculateInitialCapacity(int expectedSize) { + return (int) Math.ceil(expectedSize / 0.75); + } + + /** + * This is a temporary workaround for Java 8 specific performance issue https://bugs.openjdk.org/browse/JDK-8161372. + * Fix is available in Java 9. + *

* ConcurrentHashMap.computeIfAbsent(k,v) locks when k is present. * Add pre-screen before locking inside computeIfAbsent. *

Note: This utility is not for a general purpose usage. diff --git a/reactor-netty-core/src/main/java/reactor/netty/tcp/TcpServerBind.java b/reactor-netty-core/src/main/java/reactor/netty/tcp/TcpServerBind.java index 202febad93..87d93ecb00 100644 --- a/reactor-netty-core/src/main/java/reactor/netty/tcp/TcpServerBind.java +++ b/reactor-netty-core/src/main/java/reactor/netty/tcp/TcpServerBind.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2021 VMware, Inc. or its affiliates, All Rights Reserved. + * Copyright (c) 2017-2023 VMware, Inc. or its affiliates, All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ import io.netty.channel.ChannelOption; import reactor.core.publisher.Mono; import reactor.netty.DisposableServer; +import reactor.netty.internal.util.MapUtils; import java.net.InetSocketAddress; import java.util.Collections; @@ -37,7 +38,7 @@ final class TcpServerBind extends TcpServer { final TcpServerConfig config; TcpServerBind() { - Map, Boolean> childOptions = new HashMap<>(2); + Map, Boolean> childOptions = new HashMap<>(MapUtils.calculateInitialCapacity(2)); childOptions.put(ChannelOption.AUTO_READ, false); childOptions.put(ChannelOption.TCP_NODELAY, true); this.config = new TcpServerConfig( diff --git a/reactor-netty-core/src/main/java/reactor/netty/transport/ServerTransport.java b/reactor-netty-core/src/main/java/reactor/netty/transport/ServerTransport.java index 873851afff..70f2147b0c 100644 --- a/reactor-netty-core/src/main/java/reactor/netty/transport/ServerTransport.java +++ b/reactor-netty-core/src/main/java/reactor/netty/transport/ServerTransport.java @@ -537,7 +537,7 @@ public void disposeNow(Duration timeout) { Mono terminateSignals = Mono.empty(); if (config.channelGroup != null && config.channelGroup.size() > 0) { HashMap>> channelsToMono = - new HashMap<>((int) Math.ceil(config.channelGroup.size() / 0.75)); + new HashMap<>(MapUtils.calculateInitialCapacity(config.channelGroup.size())); // Wait for the running requests to finish for (Channel channel : config.channelGroup) { Channel parent = channel.parent(); diff --git a/reactor-netty-core/src/main/java/reactor/netty/transport/TransportConfig.java b/reactor-netty-core/src/main/java/reactor/netty/transport/TransportConfig.java index be335407eb..5a77bf4b88 100644 --- a/reactor-netty-core/src/main/java/reactor/netty/transport/TransportConfig.java +++ b/reactor-netty-core/src/main/java/reactor/netty/transport/TransportConfig.java @@ -39,6 +39,7 @@ import reactor.netty.NettyPipeline; import reactor.netty.channel.ChannelMetricsRecorder; import reactor.netty.channel.ChannelOperations; +import reactor.netty.internal.util.MapUtils; import reactor.netty.resources.LoopResources; import reactor.util.Logger; import reactor.util.Loggers; @@ -351,7 +352,7 @@ protected static Map updateMap(Map parentMap, Object key, @Nu return value == null ? parentMap : Collections.singletonMap((K) key, (V) value); } else { - Map attrs = new HashMap<>(parentMap.size() + 1); + Map attrs = new HashMap<>(MapUtils.calculateInitialCapacity(parentMap.size() + 1)); attrs.putAll(parentMap); if (value == null) { attrs.remove(key); diff --git a/reactor-netty-http/src/main/java/reactor/netty/http/server/HttpPredicate.java b/reactor-netty-http/src/main/java/reactor/netty/http/server/HttpPredicate.java index 42812fef5b..58b7deba15 100644 --- a/reactor-netty-http/src/main/java/reactor/netty/http/server/HttpPredicate.java +++ b/reactor-netty-http/src/main/java/reactor/netty/http/server/HttpPredicate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2021 VMware, Inc. or its affiliates, All Rights Reserved. + * Copyright (c) 2011-2023 VMware, Inc. or its affiliates, All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,6 +26,7 @@ import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpVersion; +import reactor.netty.internal.util.MapUtils; import reactor.util.annotation.Nullable; import static java.util.Objects.requireNonNull; @@ -344,7 +345,7 @@ public boolean matches(String uri) { * @return the path parameters from the uri. Never {@code null}. */ final Map match(String uri) { - Map pathParameters = new HashMap<>(pathVariables.size()); + Map pathParameters = new HashMap<>(MapUtils.calculateInitialCapacity(pathVariables.size())); Matcher m = matcher(uri); if (m.matches()) { diff --git a/reactor-netty-http/src/main/java/reactor/netty/http/server/HttpServerBind.java b/reactor-netty-http/src/main/java/reactor/netty/http/server/HttpServerBind.java index 3b90d1ed27..b055147544 100644 --- a/reactor-netty-http/src/main/java/reactor/netty/http/server/HttpServerBind.java +++ b/reactor-netty-http/src/main/java/reactor/netty/http/server/HttpServerBind.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2021 VMware, Inc. or its affiliates, All Rights Reserved. + * Copyright (c) 2017-2023 VMware, Inc. or its affiliates, All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ import io.netty.util.AttributeKey; import reactor.core.publisher.Mono; import reactor.netty.DisposableServer; +import reactor.netty.internal.util.MapUtils; import reactor.netty.tcp.SslProvider; import reactor.netty.tcp.TcpServerConfig; @@ -41,7 +42,7 @@ final class HttpServerBind extends HttpServer { final HttpServerConfig config; HttpServerBind() { - Map, Boolean> childOptions = new HashMap<>(2); + Map, Boolean> childOptions = new HashMap<>(MapUtils.calculateInitialCapacity(2)); childOptions.put(ChannelOption.AUTO_READ, false); childOptions.put(ChannelOption.TCP_NODELAY, true); this.config = new HttpServerConfig(