From 428e1fc9c1b15e059e4d46afb3f4a1ae148d2384 Mon Sep 17 00:00:00 2001 From: nathan Date: Sun, 6 Mar 2016 23:54:11 +0100 Subject: [PATCH] Moved RmiFieldCache into better data structure (single-writer-principle variant). code polish --- .../network/pipeline/LocalRmiDecoder.java | 43 +++----------- .../network/pipeline/LocalRmiEncoder.java | 29 +--------- .../network/pipeline/RmiFieldCache.java | 58 +++++++++++++++++++ 3 files changed, 69 insertions(+), 61 deletions(-) create mode 100644 src/dorkbox/network/pipeline/RmiFieldCache.java diff --git a/src/dorkbox/network/pipeline/LocalRmiDecoder.java b/src/dorkbox/network/pipeline/LocalRmiDecoder.java index 2bbb1c9d..3cdb1a18 100644 --- a/src/dorkbox/network/pipeline/LocalRmiDecoder.java +++ b/src/dorkbox/network/pipeline/LocalRmiDecoder.java @@ -16,47 +16,19 @@ package dorkbox.network.pipeline; import dorkbox.network.connection.ConnectionImpl; -import dorkbox.network.connection.EndPoint; -import dorkbox.network.rmi.CachedMethod; -import dorkbox.network.rmi.RMI; +import dorkbox.network.rmi.OverriddenMethods; import dorkbox.network.rmi.RemoteObject; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageDecoder; import java.lang.reflect.Field; -import java.util.ArrayList; import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; public class LocalRmiDecoder extends MessageToMessageDecoder { - private static final Map, Field[]> fieldCache = new ConcurrentHashMap, Field[]>(EndPoint.DEFAULT_THREAD_POOL_SIZE); - - static - Field[] getRmiFields(final Class clazz) { - // duplicates are OK, because they will contain the same information - Field[] rmiFields = fieldCache.get(clazz); - if (rmiFields != null) { - return rmiFields; - } - - final ArrayList fields = new ArrayList(); - - for (Field field : clazz.getDeclaredFields()) { - if (field.getAnnotation(RMI.class) != null) { - fields.add(field); - } - } - - - rmiFields = new Field[fields.size()]; - fields.toArray(rmiFields); - - fieldCache.put(clazz, rmiFields); - return rmiFields; - } + private static final RmiFieldCache fieldCache = RmiFieldCache.INSTANCE(); + private static final OverriddenMethods overriddenMethods = OverriddenMethods.INSTANCE(); public LocalRmiDecoder() { @@ -79,7 +51,7 @@ class LocalRmiDecoder extends MessageToMessageDecoder { Object localRmiObject = null; Field field; int registeredId; - final Field[] rmiFields = getRmiFields(messageClass); + final Field[] rmiFields = fieldCache.get(messageClass); for (int i = 0; i < rmiFields.length; i++) { field = rmiFields[i]; registeredId = rmiFieldIds[i]; @@ -94,12 +66,15 @@ class LocalRmiDecoder extends MessageToMessageDecoder { e.printStackTrace(); } - final Class iface = CachedMethod.overriddenReverseMethods.get(localRmiObject.getClass()); + if (localRmiObject == null) { + throw new RuntimeException("Unable to get RMI interface object for RMI implementation"); + } + + final Class iface = overriddenMethods.getReverse(localRmiObject.getClass()); if (iface == null) { throw new RuntimeException("Unable to get interface for RMI implementation"); } - RemoteObject remoteObject = connection.getProxyObject(registeredId, iface); field.set(messageObject, remoteObject); } diff --git a/src/dorkbox/network/pipeline/LocalRmiEncoder.java b/src/dorkbox/network/pipeline/LocalRmiEncoder.java index 916a19ac..2a94caac 100644 --- a/src/dorkbox/network/pipeline/LocalRmiEncoder.java +++ b/src/dorkbox/network/pipeline/LocalRmiEncoder.java @@ -23,7 +23,6 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageEncoder; import java.lang.reflect.Field; -import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.WeakHashMap; @@ -34,31 +33,7 @@ public class LocalRmiEncoder extends MessageToMessageEncoder { private static final Map, Boolean> transformObjectCache = new ConcurrentHashMap, Boolean>(EndPoint.DEFAULT_THREAD_POOL_SIZE); - private static final Map, Field[]> fieldCache = new ConcurrentHashMap, Field[]>(EndPoint.DEFAULT_THREAD_POOL_SIZE); - - static - Field[] getRmiFields(final Class clazz) { - // duplicates are OK, because they will contain the same information - Field[] rmiFields = fieldCache.get(clazz); - if (rmiFields != null) { - return rmiFields; - } - - final ArrayList fields = new ArrayList(); - - for (Field field : clazz.getDeclaredFields()) { - if (field.getAnnotation(RMI.class) != null) { - fields.add(field); - } - } - - - rmiFields = new Field[fields.size()]; - fields.toArray(rmiFields); - - fieldCache.put(clazz, rmiFields); - return rmiFields; - } + private static final RmiFieldCache fieldCache = RmiFieldCache.INSTANCE(); private final ThreadLocal> threadLocal = new ThreadLocal>() { @Override @@ -115,7 +90,7 @@ class LocalRmiEncoder extends MessageToMessageEncoder { private Object replaceFieldObjects(final ConnectionImpl connection, final Object object, final Class implClass) { - Field[] rmiFields = getRmiFields(implClass); + Field[] rmiFields = fieldCache.get(implClass); int length = rmiFields.length; Object rmiObject = null; diff --git a/src/dorkbox/network/pipeline/RmiFieldCache.java b/src/dorkbox/network/pipeline/RmiFieldCache.java new file mode 100644 index 00000000..2089baa2 --- /dev/null +++ b/src/dorkbox/network/pipeline/RmiFieldCache.java @@ -0,0 +1,58 @@ +package dorkbox.network.pipeline; + +import com.esotericsoftware.kryo.util.IdentityMap; +import dorkbox.network.rmi.RMI; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; + +/** + * Uses the "single writer principle" for fast access, but disregards 'single writer', because duplicates are OK + */ +class RmiFieldCache { + private volatile IdentityMap, Field[]> fieldCache = new IdentityMap, Field[]>(); + + private static final AtomicReferenceFieldUpdater rmiFieldsREF = + AtomicReferenceFieldUpdater.newUpdater(RmiFieldCache.class, + IdentityMap.class, + "fieldCache"); + + private static final RmiFieldCache INSTANCE = new RmiFieldCache(); + public static synchronized RmiFieldCache INSTANCE() { + return INSTANCE; + } + + private + RmiFieldCache() { + } + + Field[] get(final Class clazz) { + // duplicates are OK, because they will contain the same information, so we DO NOT care about single writers + + //noinspection unchecked + final IdentityMap, Field[]> identityMap = rmiFieldsREF.get(this); + + + Field[] rmiFields = identityMap.get(clazz); + if (rmiFields != null) { + return rmiFields; + } + + final ArrayList fields = new ArrayList(); + + for (Field field : clazz.getDeclaredFields()) { + if (field.getAnnotation(RMI.class) != null) { + fields.add(field); + } + } + + + rmiFields = new Field[fields.size()]; + fields.toArray(rmiFields); + + // save in cache + fieldCache.put(clazz, rmiFields); + return rmiFields; + } +}