Moved RmiFieldCache into better data structure (single-writer-principle variant). code polish

This commit is contained in:
nathan 2016-03-06 23:54:11 +01:00
parent 52f5c1688b
commit 428e1fc9c1
3 changed files with 69 additions and 61 deletions

View File

@ -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<Object> {
private static final Map<Class<?>, Field[]> fieldCache = new ConcurrentHashMap<Class<?>, 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<Field> fields = new ArrayList<Field>();
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> {
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<Object> {
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);
}

View File

@ -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<Object> {
private static final Map<Class<?>, Boolean> transformObjectCache = new ConcurrentHashMap<Class<?>, Boolean>(EndPoint.DEFAULT_THREAD_POOL_SIZE);
private static final Map<Class<?>, Field[]> fieldCache = new ConcurrentHashMap<Class<?>, 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<Field> fields = new ArrayList<Field>();
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<Map<Object, Integer>> threadLocal = new ThreadLocal<Map<Object, Integer>>() {
@Override
@ -115,7 +90,7 @@ class LocalRmiEncoder extends MessageToMessageEncoder<Object> {
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;

View File

@ -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<Class<?>, Field[]> fieldCache = new IdentityMap<Class<?>, Field[]>();
private static final AtomicReferenceFieldUpdater<RmiFieldCache, IdentityMap> 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<Class<?>, Field[]> identityMap = rmiFieldsREF.get(this);
Field[] rmiFields = identityMap.get(clazz);
if (rmiFields != null) {
return rmiFields;
}
final ArrayList<Field> fields = new ArrayList<Field>();
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;
}
}