From c7cf1cb45f32323281e01bd7c39beab11d037562 Mon Sep 17 00:00:00 2001 From: Richard Startin Date: Mon, 31 Oct 2022 14:57:51 +0000 Subject: [PATCH] segregate MethodHandles code from aggregation logic to make it easier to delete when increasing the language level --- .../java/com/timgroup/statsd/MapUtils.java | 52 +++++++++++++++++++ .../com/timgroup/statsd/StatsDAggregator.java | 44 +--------------- 2 files changed, 53 insertions(+), 43 deletions(-) create mode 100644 src/main/java/com/timgroup/statsd/MapUtils.java diff --git a/src/main/java/com/timgroup/statsd/MapUtils.java b/src/main/java/com/timgroup/statsd/MapUtils.java new file mode 100644 index 00000000..07164b56 --- /dev/null +++ b/src/main/java/com/timgroup/statsd/MapUtils.java @@ -0,0 +1,52 @@ +package com.timgroup.statsd; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.Map; + +/** + * MethodHandle based bridge for using JDK8+ functionality at JDK7 language level. + * Can be removed when support for JDK7 is dropped. + */ +public class MapUtils { + + private static final MethodHandle MAP_PUT_IF_ABSENT = buildMapPutIfAbsent(); + + /** + * Emulates {@code Map.putIfAbsent} semantics. Replace when baselining at JDK8+. + * @return the previous value associated with the message, or null if the value was not seen before + */ + static Message putIfAbsent(Map map, Message message) { + if (MAP_PUT_IF_ABSENT != null) { + try { + return (Message) (Object) MAP_PUT_IF_ABSENT.invokeExact(map, (Object) message, (Object) message); + } catch (Throwable ignore) { + return putIfAbsentFallback(map, message); + } + } + return putIfAbsentFallback(map, message); + } + + /** + * Emulates {@code Map.putIfAbsent} semantics. Replace when baselining at JDK8+. + * @return the previous value associated with the message, or null if the value was not seen before + */ + private static Message putIfAbsentFallback(Map map, Message message) { + if (map.containsKey(message)) { + return map.get(message); + } + map.put(message, message); + return null; + } + + private static MethodHandle buildMapPutIfAbsent() { + try { + return MethodHandles.publicLookup() + .findVirtual(Map.class, "putIfAbsent", + MethodType.methodType(Object.class, Object.class, Object.class)); + } catch (Throwable ignore) { + return null; + } + } +} diff --git a/src/main/java/com/timgroup/statsd/StatsDAggregator.java b/src/main/java/com/timgroup/statsd/StatsDAggregator.java index 97c766ea..fc8ae3c6 100644 --- a/src/main/java/com/timgroup/statsd/StatsDAggregator.java +++ b/src/main/java/com/timgroup/statsd/StatsDAggregator.java @@ -1,8 +1,5 @@ package com.timgroup.statsd; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; import java.util.ArrayList; import java.util.EnumSet; import java.util.HashMap; @@ -18,8 +15,6 @@ public class StatsDAggregator { public static int DEFAULT_SHARDS = 4; // 4 partitions to reduce contention. protected final String AGGREGATOR_THREAD_NAME = "statsd-aggregator-thread"; - - private static final MethodHandle MAP_PUT_IF_ABSENT = buildMapPutIfAbsent(); protected static final Set AGGREGATE_SET = EnumSet.of(Message.Type.COUNT, Message.Type.GAUGE, Message.Type.SET); protected final ArrayList> aggregateMetrics; @@ -109,7 +104,7 @@ public boolean aggregateMessage(Message message) { synchronized (map) { // For now let's just put the message in the map - Message msg = putIfAbsent(map, message); + Message msg = MapUtils.putIfAbsent(map, message); if (msg != null) { msg.aggregate(message); if (telemetry != null) { @@ -163,41 +158,4 @@ protected void flush() { } } } - - /** - * Emulates {@code Map.putIfAbsent} semantics. Replace when baselining at JDK8+. - * @return the previous value associated with the message, or null if the value was not seen before - */ - private static Message putIfAbsent(Map map, Message message) { - if (MAP_PUT_IF_ABSENT != null) { - try { - return (Message) (Object) MAP_PUT_IF_ABSENT.invokeExact(map, (Object) message, (Object) message); - } catch (Throwable ignore) { - return putIfAbsentFallback(map, message); - } - } - return putIfAbsentFallback(map, message); - } - - /** - * Emulates {@code Map.putIfAbsent} semantics. Replace when baselining at JDK8+. - * @return the previous value associated with the message, or null if the value was not seen before - */ - private static Message putIfAbsentFallback(Map map, Message message) { - if (map.containsKey(message)) { - return map.get(message); - } - map.put(message, message); - return null; - } - - private static MethodHandle buildMapPutIfAbsent() { - try { - return MethodHandles.publicLookup() - .findVirtual(Map.class, "putIfAbsent", - MethodType.methodType(Object.class, Object.class, Object.class)); - } catch (Throwable ignore) { - return null; - } - } }