From f52e14801bc17153f56c0c0e43099cf64a39110f Mon Sep 17 00:00:00 2001 From: J Robert Ray Date: Wed, 10 Dec 2014 15:03:45 -0800 Subject: [PATCH] Add class lookup caching to BasicStream. BasicStream#getConcreateClass is called several times for every instance of a class inside a message, leading to poor decoding performance, which becomes apparent for messages that contains sequences of classes with thousands of entries. --- java/src/IceInternal/BasicStream.java | 41 ++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/java/src/IceInternal/BasicStream.java b/java/src/IceInternal/BasicStream.java index c5bcbf5..c2b6971 100644 --- a/java/src/IceInternal/BasicStream.java +++ b/java/src/IceInternal/BasicStream.java @@ -63,6 +63,9 @@ public class BasicStream _startSeq = -1; _sizeStack = null; + + // Cache of class lookups. + _classCache = new java.util.concurrent.ConcurrentHashMap>>(); } // @@ -158,6 +161,10 @@ public class BasicStream java.util.Deque tmpSizeStack = other._sizeStack; other._sizeStack = _sizeStack; _sizeStack = tmpSizeStack; + + java.util.concurrent.ConcurrentHashMap>> tmpClassCache = other._classCache; + other._classCache = _classCache; + _classCache = tmpClassCache; } public void @@ -2683,12 +2690,37 @@ public class BasicStream return c; } + /** + * This class serves as the type for a sentinel Class instance + * to stand in for findClass() misses. + */ + private static class FindClassMiss {}; + final static Class findClassMiss = new FindClassMiss().getClass(); + final static java.lang.ref.WeakReference> findClassMissRef = new java.lang.ref.WeakReference>(findClassMiss); + private Class getConcreteClass(String className) throws LinkageError { - Class c = _instance.findClass(className); + // Check cache first. + java.lang.ref.WeakReference> ref = _classCache.get(className); + if (ref != null) + { + Class c = ref.get(); + if (c != null) { + // The 'findClassMiss' value represents a cache miss. + if (c == findClassMiss) { + return null; + } + return c; + } + else { + // Reference expired. + _classCache.remove(className); + } + } + Class c = _instance.findClass(className); if(c != null) { // @@ -2699,10 +2731,16 @@ public class BasicStream int modifiers = c.getModifiers(); if((modifiers & 0x200) == 0 && (modifiers & 0x400) == 0) { + // Cache lookup successes. + _classCache.put(className, new java.lang.ref.WeakReference>(c)); + return c; } } + // Cache lookup misses too. + _classCache.put(className, findClassMissRef); + return null; } @@ -2784,6 +2822,7 @@ public class BasicStream private byte[] _stringBytes; // Reusable array for reading strings. private char[] _stringChars; // Reusable array for reading strings. private java.util.Deque _sizeStack; + private java.util.concurrent.ConcurrentHashMap>> _classCache; private enum SliceType { NoSlice, ObjectSlice, ExceptionSlice } -- 1.8.5.2