Moved RmiFieldCache into better data structure (single-writer-principle variant). code polish
This commit is contained in:
parent
52f5c1688b
commit
428e1fc9c1
@ -16,47 +16,19 @@
|
|||||||
package dorkbox.network.pipeline;
|
package dorkbox.network.pipeline;
|
||||||
|
|
||||||
import dorkbox.network.connection.ConnectionImpl;
|
import dorkbox.network.connection.ConnectionImpl;
|
||||||
import dorkbox.network.connection.EndPoint;
|
import dorkbox.network.rmi.OverriddenMethods;
|
||||||
import dorkbox.network.rmi.CachedMethod;
|
|
||||||
import dorkbox.network.rmi.RMI;
|
|
||||||
import dorkbox.network.rmi.RemoteObject;
|
import dorkbox.network.rmi.RemoteObject;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
public
|
public
|
||||||
class LocalRmiDecoder extends MessageToMessageDecoder<Object> {
|
class LocalRmiDecoder extends MessageToMessageDecoder<Object> {
|
||||||
|
|
||||||
private static final Map<Class<?>, Field[]> fieldCache = new ConcurrentHashMap<Class<?>, Field[]>(EndPoint.DEFAULT_THREAD_POOL_SIZE);
|
private static final RmiFieldCache fieldCache = RmiFieldCache.INSTANCE();
|
||||||
|
private static final OverriddenMethods overriddenMethods = OverriddenMethods.INSTANCE();
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
public
|
||||||
LocalRmiDecoder() {
|
LocalRmiDecoder() {
|
||||||
@ -79,7 +51,7 @@ class LocalRmiDecoder extends MessageToMessageDecoder<Object> {
|
|||||||
Object localRmiObject = null;
|
Object localRmiObject = null;
|
||||||
Field field;
|
Field field;
|
||||||
int registeredId;
|
int registeredId;
|
||||||
final Field[] rmiFields = getRmiFields(messageClass);
|
final Field[] rmiFields = fieldCache.get(messageClass);
|
||||||
for (int i = 0; i < rmiFields.length; i++) {
|
for (int i = 0; i < rmiFields.length; i++) {
|
||||||
field = rmiFields[i];
|
field = rmiFields[i];
|
||||||
registeredId = rmiFieldIds[i];
|
registeredId = rmiFieldIds[i];
|
||||||
@ -94,12 +66,15 @@ class LocalRmiDecoder extends MessageToMessageDecoder<Object> {
|
|||||||
e.printStackTrace();
|
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) {
|
if (iface == null) {
|
||||||
throw new RuntimeException("Unable to get interface for RMI implementation");
|
throw new RuntimeException("Unable to get interface for RMI implementation");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RemoteObject remoteObject = connection.getProxyObject(registeredId, iface);
|
RemoteObject remoteObject = connection.getProxyObject(registeredId, iface);
|
||||||
field.set(messageObject, remoteObject);
|
field.set(messageObject, remoteObject);
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,6 @@ import io.netty.channel.ChannelHandlerContext;
|
|||||||
import io.netty.handler.codec.MessageToMessageEncoder;
|
import io.netty.handler.codec.MessageToMessageEncoder;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
@ -34,31 +33,7 @@ public
|
|||||||
class LocalRmiEncoder extends MessageToMessageEncoder<Object> {
|
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<?>, 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);
|
private static final RmiFieldCache fieldCache = RmiFieldCache.INSTANCE();
|
||||||
|
|
||||||
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 final ThreadLocal<Map<Object, Integer>> threadLocal = new ThreadLocal<Map<Object, Integer>>() {
|
private final ThreadLocal<Map<Object, Integer>> threadLocal = new ThreadLocal<Map<Object, Integer>>() {
|
||||||
@Override
|
@Override
|
||||||
@ -115,7 +90,7 @@ class LocalRmiEncoder extends MessageToMessageEncoder<Object> {
|
|||||||
|
|
||||||
private
|
private
|
||||||
Object replaceFieldObjects(final ConnectionImpl connection, final Object object, final Class<?> implClass) {
|
Object replaceFieldObjects(final ConnectionImpl connection, final Object object, final Class<?> implClass) {
|
||||||
Field[] rmiFields = getRmiFields(implClass);
|
Field[] rmiFields = fieldCache.get(implClass);
|
||||||
int length = rmiFields.length;
|
int length = rmiFields.length;
|
||||||
|
|
||||||
Object rmiObject = null;
|
Object rmiObject = null;
|
||||||
|
58
src/dorkbox/network/pipeline/RmiFieldCache.java
Normal file
58
src/dorkbox/network/pipeline/RmiFieldCache.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user