You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by rs...@apache.org on 2021/12/20 17:48:50 UTC
[avro] branch master updated: AVRO-3243: Workaround JDK-8161372 - perf issue in ConcurrentHashMap#computeIfAbsent() (#1392)
This is an automated email from the ASF dual-hosted git repository.
rskraba pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/avro.git
The following commit(s) were added to refs/heads/master by this push:
new 33d86a6 AVRO-3243: Workaround JDK-8161372 - perf issue in ConcurrentHashMap#computeIfAbsent() (#1392)
33d86a6 is described below
commit 33d86a61a9d225d83349ffbda21d2b31eeefe7ac
Author: Martin Grigorov <ma...@users.noreply.github.com>
AuthorDate: Mon Dec 20 19:47:14 2021 +0200
AVRO-3243: Workaround JDK-8161372 - perf issue in ConcurrentHashMap#computeIfAbsent() (#1392)
---
.../java/org/apache/avro/reflect/ReflectData.java | 6 ++-
.../org/apache/avro/specific/SpecificData.java | 6 ++-
.../main/java/org/apache/avro/util/MapUtil.java | 45 ++++++++++++++++++++++
.../org/apache/avro/grpc/ServiceDescriptor.java | 5 ++-
4 files changed, 56 insertions(+), 6 deletions(-)
diff --git a/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java b/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java
index 4ead6b8..1af2581 100644
--- a/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java
+++ b/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java
@@ -36,6 +36,7 @@ import org.apache.avro.io.DatumWriter;
import org.apache.avro.specific.FixedSize;
import org.apache.avro.specific.SpecificData;
import org.apache.avro.util.ClassUtils;
+import org.apache.avro.util.MapUtil;
import java.io.IOException;
import java.lang.annotation.Annotation;
@@ -63,6 +64,7 @@ import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
/** Utilities to use existing Java classes and interfaces via reflection. */
public class ReflectData extends SpecificData {
@@ -826,11 +828,11 @@ public class ReflectData extends SpecificData {
}
}
- private static final Map<Class<?>, Field[]> FIELDS_CACHE = new ConcurrentHashMap<>();
+ private static final ConcurrentMap<Class<?>, Field[]> FIELDS_CACHE = new ConcurrentHashMap<>();
// Return of this class and its superclasses to serialize.
private static Field[] getCachedFields(Class<?> recordClass) {
- return FIELDS_CACHE.computeIfAbsent(recordClass, rc -> getFields(rc, true));
+ return MapUtil.computeIfAbsent(FIELDS_CACHE, recordClass, rc -> getFields(rc, true));
}
private static Field[] getFields(Class<?> recordClass, boolean excludeJava) {
diff --git a/lang/java/avro/src/main/java/org/apache/avro/specific/SpecificData.java b/lang/java/avro/src/main/java/org/apache/avro/specific/SpecificData.java
index 5b53939..8efd904 100644
--- a/lang/java/avro/src/main/java/org/apache/avro/specific/SpecificData.java
+++ b/lang/java/avro/src/main/java/org/apache/avro/specific/SpecificData.java
@@ -30,6 +30,7 @@ import org.apache.avro.io.DatumWriter;
import org.apache.avro.io.DecoderFactory;
import org.apache.avro.io.EncoderFactory;
import org.apache.avro.util.ClassUtils;
+import org.apache.avro.util.MapUtil;
import org.apache.avro.util.internal.ClassValueCache;
import java.io.ObjectInput;
@@ -48,6 +49,7 @@ import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;
/** Utilities for generated Java classes and interfaces. */
@@ -228,7 +230,7 @@ public class SpecificData extends GenericData {
return (datum instanceof Enum) ? getSchema(datum.getClass()) : super.getEnumSchema(datum);
}
- private Map<String, Class> classCache = new ConcurrentHashMap<>();
+ private final ConcurrentMap<String, Class> classCache = new ConcurrentHashMap<>();
private static final Class NO_CLASS = new Object() {
}.getClass();
@@ -251,7 +253,7 @@ public class SpecificData extends GenericData {
String name = schema.getFullName();
if (name == null)
return null;
- Class<?> c = classCache.computeIfAbsent(name, n -> {
+ Class<?> c = MapUtil.computeIfAbsent(classCache, name, n -> {
try {
return ClassUtils.forName(getClassLoader(), getClassName(schema));
} catch (ClassNotFoundException e) {
diff --git a/lang/java/avro/src/main/java/org/apache/avro/util/MapUtil.java b/lang/java/avro/src/main/java/org/apache/avro/util/MapUtil.java
new file mode 100644
index 0000000..1bdbfaf
--- /dev/null
+++ b/lang/java/avro/src/main/java/org/apache/avro/util/MapUtil.java
@@ -0,0 +1,45 @@
+/*
+ * 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
+ *
+ * https://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.avro.util;
+
+import java.util.concurrent.ConcurrentMap;
+import java.util.function.Function;
+
+public class MapUtil {
+
+ private MapUtil() {
+ super();
+ }
+
+ /**
+ * A temporary workaround for Java 8 specific performance issue JDK-8161372
+ * .<br>
+ * This class should be removed once we drop Java 8 support.
+ *
+ * @see <a href=
+ * "https://bugs.openjdk.java.net/browse/JDK-8161372">JDK-8161372</a>
+ */
+ public static <K, V> V computeIfAbsent(ConcurrentMap<K, V> map, K key, Function<K, V> mappingFunction) {
+ V value = map.get(key);
+ if (value != null) {
+ return value;
+ }
+ return map.computeIfAbsent(key, mappingFunction::apply);
+ }
+
+}
diff --git a/lang/java/grpc/src/main/java/org/apache/avro/grpc/ServiceDescriptor.java b/lang/java/grpc/src/main/java/org/apache/avro/grpc/ServiceDescriptor.java
index 0984473..bfb8ec2 100644
--- a/lang/java/grpc/src/main/java/org/apache/avro/grpc/ServiceDescriptor.java
+++ b/lang/java/grpc/src/main/java/org/apache/avro/grpc/ServiceDescriptor.java
@@ -24,6 +24,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import io.grpc.MethodDescriptor;
+import org.apache.avro.util.MapUtil;
import static io.grpc.MethodDescriptor.generateFullMethodName;
@@ -49,7 +50,7 @@ class ServiceDescriptor {
*/
public static ServiceDescriptor create(Class iface) {
String serviceName = AvroGrpcUtils.getServiceName(iface);
- return SERVICE_DESCRIPTORS.computeIfAbsent(serviceName, key -> new ServiceDescriptor(iface, serviceName));
+ return MapUtil.computeIfAbsent(SERVICE_DESCRIPTORS, serviceName, key -> new ServiceDescriptor(iface, serviceName));
}
/**
@@ -67,7 +68,7 @@ class ServiceDescriptor {
* @return a {@link MethodDescriptor}
*/
public MethodDescriptor<Object[], Object> getMethod(String methodName, MethodDescriptor.MethodType methodType) {
- return methods.computeIfAbsent(methodName,
+ return MapUtil.computeIfAbsent(methods, methodName,
key -> MethodDescriptor.<Object[], Object>newBuilder()
.setFullMethodName(generateFullMethodName(serviceName, methodName)).setType(methodType)
.setRequestMarshaller(new AvroRequestMarshaller(protocol.getMessages().get(methodName)))