Repository: incubator-ignite Updated Branches: refs/heads/ignite-157 250dd8ea6 -> ab1f9dd27
# IGNITE-478 Refactoring Get rid GridResourceIoc.fieldCache, GridResourceIoc.mtdCache, GridResourceIoc.skipCache. Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/830a1025 Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/830a1025 Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/830a1025 Branch: refs/heads/ignite-157 Commit: 830a10252a712e2774762c9dd1be1d5df5eabe36 Parents: b210159 Author: sevdokimov <sevdoki...@gridgain.com> Authored: Thu Mar 26 17:35:25 2015 +0300 Committer: sevdokimov <sevdoki...@gridgain.com> Committed: Thu Mar 26 17:35:25 2015 +0300 ---------------------------------------------------------------------- .../processors/resource/GridResourceField.java | 11 + .../processors/resource/GridResourceIoc.java | 387 +++++++------------ .../processors/resource/GridResourceMethod.java | 13 + .../resource/GridResourceProcessor.java | 2 - .../ignite/internal/util/IgniteUtils.java | 15 + 5 files changed, 168 insertions(+), 260 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/830a1025/modules/core/src/main/java/org/apache/ignite/internal/processors/resource/GridResourceField.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/resource/GridResourceField.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/resource/GridResourceField.java index 6b921f4..162de1c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/resource/GridResourceField.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/resource/GridResourceField.java @@ -22,6 +22,7 @@ import org.jetbrains.annotations.*; import java.lang.annotation.*; import java.lang.reflect.*; +import java.util.*; /** * Wrapper for data where resource should be injected. @@ -78,6 +79,16 @@ class GridResourceField { return ann == null; } + /** + * @param c Closure. + */ + public static GridResourceField[] toArray(Collection<GridResourceField> c) { + if (c.isEmpty()) + return EMPTY_ARRAY; + + return c.toArray(new GridResourceField[c.size()]); + } + /** {@inheritDoc} */ @Override public String toString() { return S.toString(GridResourceField.class, this); http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/830a1025/modules/core/src/main/java/org/apache/ignite/internal/processors/resource/GridResourceIoc.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/resource/GridResourceIoc.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/resource/GridResourceIoc.java index 8410e71..301e5e5 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/resource/GridResourceIoc.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/resource/GridResourceIoc.java @@ -38,20 +38,8 @@ class GridResourceIoc { private final ConcurrentMap<ClassLoader, Set<Class<?>>> taskMap = new ConcurrentHashMap8<>(); - /** Field cache. */ - private final ConcurrentMap<Class<?>, ConcurrentMap<Class<? extends Annotation>, GridResourceField[]>> fieldCache = - new ConcurrentHashMap8<>(); - - /** Method cache. */ - private final ConcurrentMap<Class<?>, ConcurrentMap<Class<? extends Annotation>, GridResourceMethod[]>> mtdCache = - new ConcurrentHashMap8<>(); - - /** - * Cache for classes that do not require injection with some annotation. - * Maps annotation classes to set a set of target classes to skip. - */ - private final ConcurrentMap<Class<? extends Annotation>, Set<Class<?>>> skipCache = - new ConcurrentHashMap8<>(); + /** Class descriptors cache. */ + private final ConcurrentMap<Class<?>, ClassDescriptor> clsDescs = new ConcurrentHashMap8<>(); /** */ private final ConcurrentMap<Class<?>, Class<? extends Annotation>[]> annCache = @@ -64,18 +52,8 @@ class GridResourceIoc { Set<Class<?>> clss = taskMap.remove(ldr); if (clss != null) { - fieldCache.keySet().removeAll(clss); - mtdCache.keySet().removeAll(clss); - - for (Map.Entry<Class<? extends Annotation>, Set<Class<?>>> e : skipCache.entrySet()) { - Set<Class<?>> skipClss = e.getValue(); - - if (skipClss != null) - e.getValue().removeAll(clss); - } - - for (Class<?> cls : clss) - annCache.remove(cls); + clsDescs.keySet().removeAll(clss); + annCache.keySet().removeAll(clss); } } @@ -84,8 +62,8 @@ class GridResourceIoc { */ void undeployAll() { taskMap.clear(); - mtdCache.clear(); - fieldCache.clear(); + clsDescs.clear(); + annCache.clear(); } /** @@ -107,15 +85,27 @@ class GridResourceIoc { @Nullable Class<?> depCls) throws IgniteCheckedException { - assert target != null; - assert annCls != null; - assert injector != null; + return injectInternal(target, annCls, injector, dep, depCls, null); + } - if (isAnnotationPresent(target, annCls, dep)) - // Use identity hash set to compare via referential equality. - return injectInternal(target, annCls, injector, dep, depCls, new GridLeanIdentitySet<>()); + /** + * @param cls Class. + */ + @NotNull + private ClassDescriptor descriptor(@Nullable GridDeployment dep, Class<?> cls) { + ClassDescriptor res = clsDescs.get(cls); - return false; + if (res == null) { + if (dep != null) { + Set<Class<?>> classes = F.addIfAbsent(taskMap, dep.classLoader(), F.<Class<?>>newCSet()); + + classes.add(cls); + } + + res = F.addIfAbsent(clsDescs, cls, new ClassDescriptor(cls)); + } + + return res; } /** @@ -133,73 +123,54 @@ class GridResourceIoc { GridResourceInjector injector, @Nullable GridDeployment dep, @Nullable Class<?> depCls, - Set<Object> checkedObjs) + @Nullable Set<Object> checkedObjs) throws IgniteCheckedException { - assert target != null; - assert annCls != null; - assert injector != null; - assert checkedObjs != null; - Class<?> targetCls = target.getClass(); - Set<Class<?>> skipClss = skipCache.get(annCls); + ClassDescriptor descr = descriptor(dep, targetCls); - // Skip this class if it does not need to be injected. - if (skipClss != null && skipClss.contains(targetCls)) - return false; + T2<GridResourceField[], GridResourceMethod[]> annotatedMembers = descr.annotatedMembers(annCls); - // Check if already inspected to avoid indefinite recursion. - if (!checkedObjs.add(target)) + if (descr.recursiveFields().length == 0 && annotatedMembers == null) return false; - int annCnt = 0; + if (checkedObjs == null && descr.recursiveFields().length > 0) + checkedObjs = new GridLeanIdentitySet<>(); - boolean injected = false; + if (checkedObjs != null && !checkedObjs.add(target)) + return false; - for (GridResourceField field : getFieldsWithAnnotation(dep, targetCls, annCls)) { - if (field.processFieldValue()) { - Field f = field.getField(); + boolean injected = false; - try { - Object obj = f.get(target); + for (GridResourceField field : descr.recursiveFields()) { + try { + Object obj = field.getField().get(target); - if (obj != null) { - // Recursion. - boolean injected0 = injectInternal(obj, annCls, injector, dep, depCls, checkedObjs); + if (obj != null) { + assert checkedObjs != null; - injected |= injected0; - } - } - catch (IllegalAccessException e) { - throw new IgniteCheckedException("Failed to inject resource [field=" + f.getName() + - ", target=" + target + ']', e); + injected |= injectInternal(obj, annCls, injector, dep, depCls, checkedObjs); } } - else { - injector.inject(field, target, depCls, dep); - - injected = true; + catch (IllegalAccessException e) { + throw new IgniteCheckedException("Failed to inject resource [field=" + field.getField().getName() + + ", target=" + target + ']', e); } - - annCnt++; } - for (GridResourceMethod mtd : getMethodsWithAnnotation(dep, targetCls, annCls)) { - injector.inject(mtd, target, depCls, dep); - - injected = true; - - annCnt++; - } + if (annotatedMembers != null) { + for (GridResourceField field : annotatedMembers.get1()) { + injector.inject(field, target, depCls, dep); - if (annCnt == 0) { - if (skipClss == null) - skipClss = F.addIfAbsent(skipCache, annCls, F.<Class<?>>newCSet()); + injected = true; + } - assert skipClss != null; + for (GridResourceMethod mtd : annotatedMembers.get2()) { + injector.inject(mtd, target, depCls, dep); - skipClss.add(targetCls); + injected = true; + } } return injected; @@ -217,29 +188,9 @@ class GridResourceIoc { assert target != null; assert annCls != null; - Class<?> targetCls = target.getClass(); - - Set<Class<?>> skipClss = skipCache.get(annCls); - - if (skipClss != null && skipClss.contains(targetCls)) - return false; - - GridResourceField[] fields = getFieldsWithAnnotation(dep, targetCls, annCls); - - if (fields.length > 0) - return true; + ClassDescriptor desc = descriptor(dep, target.getClass()); - GridResourceMethod[] mtds = getMethodsWithAnnotation(dep, targetCls, annCls); - - if (mtds.length > 0) - return true; - - if (skipClss == null) - skipClss = F.addIfAbsent(skipCache, annCls, F.<Class<?>>newCSet()); - - skipClss.add(targetCls); - - return false; + return desc.recursiveFields().length > 0 || desc.annotatedMembers(annCls) != null; } /** @@ -260,17 +211,14 @@ class GridResourceIoc { Class<? extends Annotation>[] res = annCache.get(cls); if (res == null) { - Collection<Class<? extends Annotation>> res0 = - new HashSet<>(annClss.size(), 1.0f); + Collection<Class<? extends Annotation>> res0 = new ArrayList<>(); for (Class<? extends Annotation> annCls : annClss) { if (isAnnotationPresent(target, annCls, dep)) res0.add(annCls); } - res = new Class[res0.size()]; - - res0.toArray(res); + res = res0.toArray(new Class[res0.size()]); annCache.putIfAbsent(cls, res); } @@ -279,36 +227,6 @@ class GridResourceIoc { } /** - * For tests only. - * - * @param cls Class for test. - * @return {@code true} if cached, {@code false} otherwise. - */ - boolean isCached(Class<?> cls) { - return isCached(cls.getName()); - } - - /** - * For tests only. - * - * @param clsName Class for test. - * @return {@code true} if cached, {@code false} otherwise. - */ - boolean isCached(String clsName) { - for (Class<?> aClass : fieldCache.keySet()) { - if (aClass.getName().equals(clsName)) - return true; - } - - for (Class<?> aClass : mtdCache.keySet()) { - if (aClass.getName().equals(clsName)) - return true; - } - - return false; - } - - /** * Gets set of methods with given annotation. * * @param dep Deployment. @@ -318,156 +236,109 @@ class GridResourceIoc { */ GridResourceMethod[] getMethodsWithAnnotation(@Nullable GridDeployment dep, Class<?> cls, Class<? extends Annotation> annCls) { - GridResourceMethod[] mtds = getMethodsFromCache(cls, annCls); + ClassDescriptor desc = descriptor(dep, cls); - if (mtds == null) { - List<GridResourceMethod> mtdsList = new ArrayList<>(); - - for (Class cls0 = cls; !cls0.equals(Object.class); cls0 = cls0.getSuperclass()) { - for (Method mtd : cls0.getDeclaredMethods()) { - Annotation ann = mtd.getAnnotation(annCls); - - if (ann != null) - mtdsList.add(new GridResourceMethod(mtd, ann)); - } - } + T2<GridResourceField[], GridResourceMethod[]> t2 = desc.annotatedMembers(annCls); - if (mtdsList.isEmpty()) - mtds = GridResourceMethod.EMPTY_ARRAY; - else - mtds = mtdsList.toArray(new GridResourceMethod[mtdsList.size()]); - - cacheMethods(dep, cls, annCls, mtds); - } + return t2 == null ? GridResourceMethod.EMPTY_ARRAY : t2.get2(); + } - return mtds; + /** {@inheritDoc} */ + public void printMemoryStats() { + X.println(">>> taskMapSize: " + taskMap.size()); + X.println(">>> classDescriptorsCacheSize: " + clsDescs.size()); } /** - * Gets all entries from the specified class or its super-classes that have - * been annotated with annotation provided. * - * @param cls Class in which search for methods. - * @param dep Deployment. - * @param annCls Annotation. - * @return Set of entries with given annotations. */ - private GridResourceField[] getFieldsWithAnnotation(@Nullable GridDeployment dep, Class<?> cls, - Class<? extends Annotation> annCls) { - GridResourceField[] fields = getFieldsFromCache(cls, annCls); + private static class ClassDescriptor { + /** */ + private final GridResourceField[] recursiveFields; + + /** */ + private final Map<Class<? extends Annotation>, T2<GridResourceField[], GridResourceMethod[]>> annMap; + + /** + * @param cls Class. + */ + ClassDescriptor(Class<?> cls) { + Map<Class<? extends Annotation>, T2<List<GridResourceField>, List<GridResourceMethod>>> annMap + = new HashMap<>(); - if (fields == null) { - List<GridResourceField> fieldsList = new ArrayList<>(); + Collection<GridResourceField> recursiveFieldsList = new ArrayList<>(); boolean allowImplicitInjection = !GridNoImplicitInjection.class.isAssignableFrom(cls); for (Class cls0 = cls; !cls0.equals(Object.class); cls0 = cls0.getSuperclass()) { for (Field field : cls0.getDeclaredFields()) { - Annotation ann = field.getAnnotation(annCls); - - if (ann != null) - fieldsList.add(new GridResourceField(field, ann)); - else if (allowImplicitInjection && GridResourceUtils.mayRequireResources(field)) { - // Account for anonymous inner classes. - fieldsList.add(new GridResourceField(field, null)); - } - } - } - - if (fieldsList.isEmpty()) - fields = GridResourceField.EMPTY_ARRAY; - else - fields = fieldsList.toArray(new GridResourceField[fieldsList.size()]); + Annotation[] fieldAnns = field.getAnnotations(); - cacheFields(dep, cls, annCls, fields); - } + for (Annotation ann : fieldAnns) { + T2<List<GridResourceField>, List<GridResourceMethod>> t2 = annMap.get(ann.annotationType()); - return fields; - } + if (t2 == null) { + t2 = new T2<List<GridResourceField>, List<GridResourceMethod>>( + new ArrayList<GridResourceField>(), + new ArrayList<GridResourceMethod>()); - /** - * Gets all fields for a given class with given annotation from cache. - * - * @param cls Class to get fields from. - * @param annCls Annotation class for fields. - * @return List of fields with given annotation, possibly {@code null}. - */ - @Nullable private GridResourceField[] getFieldsFromCache(Class<?> cls, Class<? extends Annotation> annCls) { - Map<Class<? extends Annotation>, GridResourceField[]> annCache = fieldCache.get(cls); + annMap.put(ann.annotationType(), t2); + } - return annCache != null ? annCache.get(annCls) : null; - } - - /** - * Caches list of fields with given annotation from given class. - * - * @param cls Class the fields belong to. - * @param dep Deployment. - * @param annCls Annotation class for the fields. - * @param fields Fields to cache. - */ - private void cacheFields(@Nullable GridDeployment dep, Class<?> cls, Class<? extends Annotation> annCls, - GridResourceField[] fields) { - if (dep != null) { - Set<Class<?>> classes = F.addIfAbsent(taskMap, dep.classLoader(), F.<Class<?>>newCSet()); + t2.get1().add(new GridResourceField(field, ann)); + } - assert classes != null; + if (allowImplicitInjection + && fieldAnns.length == 0 + && GridResourceUtils.mayRequireResources(field)) { + // Account for anonymous inner classes. + recursiveFieldsList.add(new GridResourceField(field, null)); + } + } - classes.add(cls); - } + for (Method mtd : cls0.getDeclaredMethods()) { + for (Annotation ann : mtd.getAnnotations()) { + T2<List<GridResourceField>, List<GridResourceMethod>> t2 = annMap.get(ann.annotationType()); - Map<Class<? extends Annotation>, GridResourceField[]> rsrcFields = - F.addIfAbsent(fieldCache, cls, F.<Class<? extends Annotation>, GridResourceField[]>newCMap()); + if (t2 == null) { + t2 = new T2<List<GridResourceField>, List<GridResourceMethod>>( + new ArrayList<GridResourceField>(), + new ArrayList<GridResourceMethod>()); - assert rsrcFields != null; + annMap.put(ann.annotationType(), t2); + } - rsrcFields.put(annCls, fields); - } + t2.get2().add(new GridResourceMethod(mtd, ann)); + } + } + } - /** - * Gets all methods for a given class with given annotation from cache. - * - * @param cls Class to get methods from. - * @param annCls Annotation class for fields. - * @return List of methods with given annotation, possibly {@code null}. - */ - @Nullable private GridResourceMethod[] getMethodsFromCache(Class<?> cls, Class<? extends Annotation> annCls) { - Map<Class<? extends Annotation>, GridResourceMethod[]> annCache = mtdCache.get(cls); + recursiveFields = GridResourceField.toArray(recursiveFieldsList); - return annCache != null ? annCache.get(annCls) : null; - } + this.annMap = IgniteUtils.limitedMap(annMap.size()); - /** - * Caches list of methods with given annotation from given class. - * - * @param rsrcCls Class the fields belong to. - * @param dep Deployment. - * @param annCls Annotation class for the fields. - * @param mtds Methods to cache. - */ - private void cacheMethods(@Nullable GridDeployment dep, Class<?> rsrcCls, Class<? extends Annotation> annCls, - GridResourceMethod[] mtds) { - if (dep != null) { - Set<Class<?>> classes = F.addIfAbsent(taskMap, dep.classLoader(), F.<Class<?>>newCSet()); + for (Map.Entry<Class<? extends Annotation>, T2<List<GridResourceField>, List<GridResourceMethod>>> entry + : annMap.entrySet()) { - assert classes != null; + GridResourceField[] fields = GridResourceField.toArray(entry.getValue().get1()); + GridResourceMethod[] mtds = GridResourceMethod.toArray(entry.getValue().get2()); - classes.add(rsrcCls); + this.annMap.put(entry.getKey(), new T2<>(fields, mtds)); + } } - Map<Class<? extends Annotation>, GridResourceMethod[]> rsrcMtds = F.addIfAbsent(mtdCache, - rsrcCls, F.<Class<? extends Annotation>, GridResourceMethod[]>newCMap()); - - assert rsrcMtds != null; - - rsrcMtds.put(annCls, mtds); - } + /** + * @return Recursive fields. + */ + public GridResourceField[] recursiveFields() { + return recursiveFields; + } - /** {@inheritDoc} */ - public void printMemoryStats() { - X.println(">>> taskMapSize: " + taskMap.size()); - X.println(">>> fieldCacheSize: " + fieldCache.size()); - X.println(">>> mtdCacheSize: " + mtdCache.size()); - X.println(">>> skipCacheSize: " + skipCache.size()); + /** + * @return Fields. + */ + @Nullable public T2<GridResourceField[], GridResourceMethod[]> annotatedMembers(Class<? extends Annotation> annCls) { + return annMap.get(annCls); + } } } http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/830a1025/modules/core/src/main/java/org/apache/ignite/internal/processors/resource/GridResourceMethod.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/resource/GridResourceMethod.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/resource/GridResourceMethod.java index aba9405..ad08a40 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/resource/GridResourceMethod.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/resource/GridResourceMethod.java @@ -21,6 +21,7 @@ import org.apache.ignite.internal.util.typedef.internal.*; import java.lang.annotation.*; import java.lang.reflect.*; +import java.util.*; /** * Wrapper for data where resource should be injected. @@ -48,6 +49,8 @@ class GridResourceMethod { this.mtd = mtd; this.ann = ann; + + mtd.setAccessible(true); } /** @@ -68,6 +71,16 @@ class GridResourceMethod { return ann; } + /** + * @param c Closure. + */ + public static GridResourceMethod[] toArray(Collection<GridResourceMethod> c) { + if (c.isEmpty()) + return EMPTY_ARRAY; + + return c.toArray(new GridResourceMethod[c.size()]); + } + /** {@inheritDoc} */ @Override public String toString() { return S.toString(GridResourceMethod.class, this); http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/830a1025/modules/core/src/main/java/org/apache/ignite/internal/processors/resource/GridResourceProcessor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/resource/GridResourceProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/resource/GridResourceProcessor.java index f08a287..eae5c4b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/resource/GridResourceProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/resource/GridResourceProcessor.java @@ -147,8 +147,6 @@ public class GridResourceProcessor extends GridProcessorAdapter { Method mtd = rsrcMtd.getMethod(); try { - mtd.setAccessible(true); - mtd.invoke(target); } catch (IllegalArgumentException | InvocationTargetException | IllegalAccessException e) { http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/830a1025/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java index 5f6da0f..6b04fac 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java @@ -8757,6 +8757,21 @@ public abstract class IgniteUtils { } /** + * Creates new map that limited by size. + * + * @param limit Limit for size. + */ + public static <K, V> Map<K, V> limitedMap(int limit) { + if (limit == 0) + return Collections.emptyMap(); + + if (limit < 5) + return new GridLeanMap<>(limit); + + return new HashMap<>(capacity(limit), 0.75f); + } + + /** * Returns comparator that sorts remote node addresses. If remote node resides on the same host, then put * loopback addresses first, last otherwise. *