From a15116c96cb263fc42b14e522a17356adc2937f6 Mon Sep 17 00:00:00 2001 From: Armin Date: Mon, 28 Aug 2017 15:11:26 +0200 Subject: [PATCH] #7712 & #7945 BiValue Improvements * Turn Enum into HashMap for direct lookup * Use stateless Lambdas instead of named classes as converter functions for better performance * Remove redundant instanceof checks by splitting existing converter functions between Java and Ruby version * Use most restrictive instanceof check possible for Ruby converters for performance improvements Fixes #8087 --- .../java/org/logstash/bivalues/BiValues.java | 145 ++++-------------- 1 file changed, 34 insertions(+), 111 deletions(-) diff --git a/logstash-core/src/main/java/org/logstash/bivalues/BiValues.java b/logstash-core/src/main/java/org/logstash/bivalues/BiValues.java index 64229ff87..8a7d9c4aa 100644 --- a/logstash-core/src/main/java/org/logstash/bivalues/BiValues.java +++ b/logstash-core/src/main/java/org/logstash/bivalues/BiValues.java @@ -3,135 +3,58 @@ package org.logstash.bivalues; import java.math.BigDecimal; import java.math.BigInteger; import java.util.HashMap; +import java.util.Map; import org.jruby.RubyBignum; +import org.jruby.RubyFixnum; import org.jruby.RubyInteger; +import org.jruby.RubyNil; import org.jruby.RubySymbol; import org.jruby.ext.bigdecimal.RubyBigDecimal; +import org.jruby.java.proxies.ConcreteJavaProxy; import org.jruby.java.proxies.JavaProxy; -import org.jruby.runtime.builtin.IRubyObject; -public enum BiValues { - JAVA_LANG_INTEGER(BiValueType.INT), - JAVA_LANG_LONG(BiValueType.LONG), - JAVA_MATH_BIGDECIMAL(BiValueType.DECIMAL), - JAVA_MATH_BIGINTEGER(BiValueType.BIGINT), - ORG_JRUBY_EXT_BIGDECIMAL_RUBYBIGDECIMAL(BiValueType.DECIMAL), - ORG_JRUBY_JAVA_PROXIES_CONCRETEJAVAPROXY(BiValueType.JAVAPROXY), - ORG_JRUBY_RUBYBIGNUM(BiValueType.BIGINT), - ORG_JRUBY_RUBYFIXNUM(BiValueType.LONG), - ORG_JRUBY_RUBYINTEGER(BiValueType.LONG), - ORG_JRUBY_RUBYNIL(BiValueType.NULL), - ORG_JRUBY_RUBYSYMBOL(BiValueType.SYMBOL), // one way conversion, a Java string will use STRING - NULL(BiValueType.NULL); - - private static HashMap initCache() { - HashMap hm = new HashMap<>(); - hm.put("java.lang.Integer", "JAVA_LANG_INTEGER"); - hm.put("java.lang.Long", "JAVA_LANG_LONG"); - hm.put("java.math.BigDecimal", "JAVA_MATH_BIGDECIMAL"); - hm.put("java.math.BigInteger", "JAVA_MATH_BIGINTEGER"); - hm.put("org.jruby.RubyBignum", "ORG_JRUBY_RUBYBIGNUM"); - hm.put("org.jruby.RubyFixnum", "ORG_JRUBY_RUBYFIXNUM"); - hm.put("org.jruby.RubyInteger", "ORG_JRUBY_RUBYINTEGER"); - hm.put("org.jruby.RubyNil", "ORG_JRUBY_RUBYNIL"); - hm.put("org.jruby.RubySymbol", "ORG_JRUBY_RUBYSYMBOL"); - hm.put("org.jruby.ext.bigdecimal.RubyBigDecimal", "ORG_JRUBY_EXT_BIGDECIMAL_RUBYBIGDECIMAL"); - hm.put("org.jruby.java.proxies.ConcreteJavaProxy", "ORG_JRUBY_JAVA_PROXIES_CONCRETEJAVAPROXY"); - return hm; +public final class BiValues { + private BiValues() { } public static final NullBiValue NULL_BI_VALUE = NullBiValue.newNullBiValue(); - private final BiValueType biValueType; - - BiValues(BiValueType biValueType) { - this.biValueType = biValueType; - } - - private static final HashMap NAME_CACHE = initCache(); - - private BiValue build(Object value) { - return biValueType.build(value); - } + private static final Map, BiValues.BiValueType> CONVERTER_CACHE = initCache(); public static BiValue newBiValue(Object o) { if (o == null) { return NULL_BI_VALUE; } - return valueOf(fetchName(o)).build(o); - } - - private static String fetchName(Object o) { - final String cls = o.getClass().getName(); - final String name = NAME_CACHE.get(cls); - if (name != null) { - return name; + final Class cls = o.getClass(); + final BiValues.BiValueType type = CONVERTER_CACHE.get(cls); + if (type == null) { + throw new IllegalArgumentException("Unsupported class " + cls); } - return cacheName(cls); - } - - private static String cacheName(final String cls) { - final String toCache = cls.toUpperCase().replace('.', '_'); - // TODO[Guy] log warn that we are seeing a uncached value - NAME_CACHE.put(cls, toCache); - return toCache; + return type.build(o); } - private enum BiValueType { - SYMBOL { - BiValue build(Object value) { - if (value instanceof IRubyObject) { - return new SymbolBiValue((RubySymbol) value); - } - return new SymbolBiValue((String) value); - } - }, - LONG { - BiValue build(Object value) { - if (value instanceof IRubyObject) { - return new LongBiValue((RubyInteger) value); - } - return new LongBiValue((Long) value); - } - }, - INT { - BiValue build(Object value) { - if (value instanceof IRubyObject) { - return new IntegerBiValue((RubyInteger) value); - } - return new IntegerBiValue((Integer) value); - } - }, - DECIMAL { - BiValue build(Object value) { - if (value instanceof IRubyObject) { - return new BigDecimalBiValue((RubyBigDecimal) value); - } - return new BigDecimalBiValue((BigDecimal) value); - } - }, - NULL { - NullBiValue build(Object value) { - return NULL_BI_VALUE; - } - }, - BIGINT { - BiValue build(Object value) { - if (value instanceof IRubyObject) { - return new BigIntegerBiValue((RubyBignum) value); - } - return new BigIntegerBiValue((BigInteger) value); - } - }, - JAVAPROXY { - BiValue build(Object value) { - if (value instanceof IRubyObject) { - return new JavaProxyBiValue((JavaProxy) value); - } - return new JavaProxyBiValue(value); - } - }; - abstract BiValue build(Object value); + private interface BiValueType { + BiValue build(Object value); } + private static Map, BiValues.BiValueType> initCache() { + final Map, BiValues.BiValueType> hm = new HashMap<>(50, 0.2F); + hm.put(Integer.class, value -> new IntegerBiValue((Integer) value)); + hm.put(Long.class, value -> new LongBiValue((Long) value)); + hm.put(BigDecimal.class, value -> new BigDecimalBiValue((BigDecimal) value)); + hm.put(BigInteger.class, value -> new BigIntegerBiValue((BigInteger) value)); + hm.put(RubyBignum.class, value -> new BigIntegerBiValue((RubyBignum) value)); + hm.put(RubyFixnum.class, value -> new LongBiValue((RubyInteger) value)); + hm.put(RubyInteger.class, value -> new IntegerBiValue((RubyInteger) value)); + hm.put(RubyNil.class, value -> NULL_BI_VALUE); + hm.put(RubySymbol.class, value -> new SymbolBiValue((RubySymbol) value)); + hm.put(RubyBigDecimal.class, value -> new BigDecimalBiValue((RubyBigDecimal) value)); + hm.put(ConcreteJavaProxy.class, value -> { + if (value instanceof JavaProxy) { + return new JavaProxyBiValue((JavaProxy) value); + } + return new JavaProxyBiValue(value); + }); + return hm; + } }