From: Tuukka Lehtonen Date: Fri, 17 Aug 2018 08:23:20 +0000 (+0300) Subject: Improved Bindings.getBinding(Class) caching for Datatype.class X-Git-Tag: v1.43.0~136^2~408 X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=commitdiff_plain;h=a1696e5257fae039410c924155fdeffc1ce1b3e9;hp=286183f3501ea34badb28d05bd8de954eff9b8bc Improved Bindings.getBinding(Class) caching for Datatype.class Previously Datatype.class binding was never cached nor statically constructed and made available as Bindings.DATATYPE which is only sensible because Datatype class is a central building block of Databoard and therefore its binding should also be readily available instead of all clients having to request for it separately. A weak hashmap cache was also added for signature strings in BindingRequest because it was noticed that in conditions where code makes a lot of requests for uncached binding, the cost of String construction in BindingRequest.getSignature starts to dominate cpu/memory costs. Two main problems in there were: constantly creating new strings and using the very inefficient String.replaceAll instead of String.replace(char, char). gitlab #82 Change-Id: I50fbbc2bbe1e5d6b8b5864c3aed4c228022e66dc --- diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/Bindings.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/Bindings.java index 266391fa9..138ca5c05 100644 --- a/bundles/org.simantics.databoard/src/org/simantics/databoard/Bindings.java +++ b/bundles/org.simantics.databoard/src/org/simantics/databoard/Bindings.java @@ -134,7 +134,8 @@ public class Bindings { public static final VariantBinding STR_VARIANT; // java.lang.String ( as variant ) public static final Binding VOID; // void ( as {} ) - public static final Binding BEAN; // Bean ( as variant ) + public static final Binding BEAN; // Bean ( as variant ) + public static final Binding DATATYPE; // org.simantics.databoard.type.Datatype public static final ArrayBinding BOOLEAN_ARRAY; // boolean[] public static final ArrayBinding BYTE_ARRAY; // byte[] @@ -890,7 +891,9 @@ public class Bindings { OBJECT = databoard.OBJECT; databoard.initialize(); + + DATATYPE = getBindingUnchecked(Datatype.class); } - + } diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/Databoard.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/Databoard.java index ef4b0732d..da488e0a8 100644 --- a/bundles/org.simantics.databoard/src/org/simantics/databoard/Databoard.java +++ b/bundles/org.simantics.databoard/src/org/simantics/databoard/Databoard.java @@ -153,6 +153,7 @@ public class Databoard { BindingRequest br = new BindingRequest( Datatype.class ); Binding datatypeBinding = getBinding( br ); typeClassFactory.getRepository().put(datatypeBinding.type(), br); + bindingRepository.put(br, datatypeBinding); } catch (ClassNotFoundException e) { } catch (InstantiationException e) { } catch (IllegalAccessException e) { diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/VariantBinding.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/VariantBinding.java index 30fe63ffa..60e014090 100644 --- a/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/VariantBinding.java +++ b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/VariantBinding.java @@ -174,11 +174,10 @@ public abstract class VariantBinding extends Binding { @Override public int deepHashValue(Object value, IdentityHashMap hashedObjects) throws BindingException { - Datatype type = getContentType(value); + Datatype type = getContentType(value); Binding binding = getContentBinding(value); - Binding dataTypeBinding = Bindings.getBindingUnchecked(Datatype.class); Object element = getContent(value, binding); - return dataTypeBinding.deepHashValue(type, hashedObjects) + binding.deepHashValue(element, hashedObjects); + return Bindings.DATATYPE.deepHashValue(type, hashedObjects) + binding.deepHashValue(element, hashedObjects); } @Override @@ -188,8 +187,7 @@ public abstract class VariantBinding extends Binding { // Compare Type Datatype t1 = getContentType(o1); Datatype t2 = getContentType(o2); - Binding dataTypeBinding = Bindings.getBindingUnchecked(Datatype.class); - int dif = dataTypeBinding.compare(t1, t2); + int dif = Bindings.DATATYPE.compare(t1, t2); if (dif!=0) return dif; // Compare Value Binding bi1 = getContentBinding(o1); diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/factory/BindingRepository.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/factory/BindingRepository.java index 4680eee6a..ba2435371 100644 --- a/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/factory/BindingRepository.java +++ b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/factory/BindingRepository.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2011 Association for Decentralized Information Management in + * Copyright (c) 2007, 2018 Association for Decentralized Information Management in * Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -8,6 +8,7 @@ * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation + * Semantum Oy - gitlab #82 *******************************************************************************/ package org.simantics.databoard.binding.factory; @@ -17,6 +18,7 @@ import java.util.Map.Entry; import org.simantics.databoard.binding.Binding; import org.simantics.databoard.binding.reflection.BindingRequest; +import org.simantics.databoard.type.Datatype; public class BindingRepository { @@ -114,9 +116,20 @@ public class BindingRepository { classMap.clear(); } + /** + * {@link Datatype} class has annotations but it can be considered a "class + * request" as it is a fundamental building block of Databoard and it has a + * fixed structure. Therefore {@link #classMap} is allowed to contain a cached + * Datatype.class -> Binding mapping. + */ + private static final String DATATYPE_CLASS_NAME = Datatype.class.getName(); + boolean isClassRequest( BindingRequest request ) { - return request.className != null && (request.annotations==null || request.annotations.length==0); + return (request.className != null + && ((request.annotations==null || request.annotations.length==0) + || DATATYPE_CLASS_NAME.equals(request.className)) + ); } } diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/reflection/BindingRequest.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/reflection/BindingRequest.java index 4ada93603..51feb39c3 100644 --- a/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/reflection/BindingRequest.java +++ b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/reflection/BindingRequest.java @@ -1,3 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 Association for Decentralized Information Management in + * Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + * Semantum Oy - gitlab #82 + *******************************************************************************/ package org.simantics.databoard.binding.reflection; import java.lang.annotation.Annotation; @@ -6,13 +18,25 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.WeakHashMap; + import org.simantics.databoard.annotations.ArgumentImpl; import org.simantics.databoard.annotations.Arguments; import org.simantics.databoard.binding.Binding; import org.simantics.databoard.primitives.MutableInteger; public class BindingRequest { - + + /** + * A weak cache for signature strings by Class. + * Prevents the system from constructing new strings + * from Classes for every non-trivial BindingRequest. + */ + private static final Map, String> signatureCache = Collections., String>synchronizedMap(new WeakHashMap<>()); + + public static final Annotation[] NO_ANNOTATIONS = {}; + public static BindingRequest create( Field field ) { Annotation[] annotations = ClassBindingFactory.getFieldAnnotations(field); @@ -27,8 +51,6 @@ public class BindingRequest { /** Annotations */ public final Annotation[] annotations; - public final Annotation[] NO_ANNOTATIONS = new Annotation[0]; - public final String className; // eg. java.util.Map public final String signature; // eg. Ljava/util/Map; public final String descriptor; //eg. Ljava/util/Map; @@ -59,7 +81,18 @@ public class BindingRequest { hash = 7*hash + a.hashCode(); } } - + + /** + * Create BindingRequest + * + * @param clazz + * @param annotations + */ + public BindingRequest(Class clazz) + { + this(clazz, NO_ANNOTATIONS); + } + /** * Create BindingRequest * @@ -221,8 +254,17 @@ public class BindingRequest { if (clazz==float.class) return "F"; if (clazz==long.class) return "J"; if (clazz==double.class) return "D"; - if (clazz.isArray()) return clazz.getName().replaceAll("\\.", "/"); - return "L"+clazz.getName().replaceAll("\\.", "/")+";"; + String cached = signatureCache.get(clazz); + if (cached == null) { + cached = clazz.isArray() + ? clazz.getName().replace('.', '/') + : "L"+clazz.getName().replace('.', '/')+";"; + signatureCache.put(clazz, cached); + //System.out.println("BindingRequest.getSignature: cache miss for " + clazz + " = " + cached); + } else { + //System.out.println("BindingRequest.getSignature: cache hit for " + clazz + " = " + cached); + } + return cached; } @SuppressWarnings("unchecked") diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/request/PropertyInfo.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/request/PropertyInfo.java index aafcef3b2..f3753ce80 100644 --- a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/request/PropertyInfo.java +++ b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/request/PropertyInfo.java @@ -51,7 +51,7 @@ public class PropertyInfo { if(literalRange != null) { Collection dts = graph.getAssertedObjects(literalRange, L0.HasDataType); if(dts.size() == 1) { - Datatype dt = graph.getPossibleValue(dts.iterator().next(), Bindings.getBindingUnchecked(Datatype.class)); + Datatype dt = graph.getPossibleValue(dts.iterator().next(), Bindings.DATATYPE); if(requiredDatatype == null) requiredDatatype = dt; } }