You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2018/08/31 23:46:43 UTC

[isis] 01/06: ISIS-1974: introspects in parallel

This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a commit to branch maint-1.16.2
in repository https://gitbox.apache.org/repos/asf/isis.git

commit b3eb20c97ab14bf8951018149b7cc71ba0533c73
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Sun Aug 26 23:31:04 2018 +0100

    ISIS-1974: introspects in parallel
---
 .../metamodel/specloader/SpecificationLoader.java  | 83 +++++++++++++++++++---
 .../specimpl/dflt/ObjectSpecificationDefault.java  |  1 -
 .../core/runtime/threadpool/ThreadPoolSupport.java | 47 ++++++++++--
 .../dflt/ProgrammingModelForObjectSpecIdFacet.java | 45 ++++++++++++
 .../system/session/IsisSessionFactoryBuilder.java  |  3 +-
 5 files changed, 161 insertions(+), 18 deletions(-)

diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java
index ca81150..81f39e8 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java
@@ -20,7 +20,10 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Properties;
 import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
 
 import com.google.common.base.Function;
 import com.google.common.collect.Lists;
@@ -40,6 +43,7 @@ import org.apache.isis.core.commons.exceptions.IsisException;
 import org.apache.isis.core.commons.lang.ClassUtil;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facets.FacetFactory;
+import org.apache.isis.core.metamodel.facets.MethodRemoverConstants;
 import org.apache.isis.core.metamodel.facets.object.autocomplete.AutoCompleteFacet;
 import org.apache.isis.core.metamodel.facets.object.objectspecid.ObjectSpecIdFacet;
 import org.apache.isis.core.metamodel.layoutmetadata.LayoutMetadataReader;
@@ -58,7 +62,9 @@ import org.apache.isis.core.metamodel.specloader.specimpl.dflt.ObjectSpecificati
 import org.apache.isis.core.metamodel.specloader.specimpl.standalonelist.ObjectSpecificationOnStandaloneList;
 import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidator;
 import org.apache.isis.core.metamodel.specloader.validator.ValidationFailures;
+import org.apache.isis.core.runtime.threadpool.ThreadPoolSupport;
 import org.apache.isis.progmodels.dflt.ProgrammingModelFacetsJava5;
+import org.apache.isis.progmodels.dflt.ProgrammingModelForObjectSpecIdFacet;
 
 /**
  * Builds the meta-model.
@@ -93,6 +99,8 @@ public class SpecificationLoader implements ApplicationScopedComponent {
     private final ProgrammingModel programmingModel;
     private final FacetProcessor facetProcessor;
 
+    FacetProcessor facetProcessorObjectSpecId;
+
     private final IsisConfiguration configuration;
     private final ServicesInjector servicesInjector;
 
@@ -101,6 +109,13 @@ public class SpecificationLoader implements ApplicationScopedComponent {
     private final List<LayoutMetadataReader> layoutMetadataReaders;
     private final PostProcessor postProcessor;
 
+    enum State {
+        NOT_INITIALIZED,
+        CACHING,
+        INTROSPECTING
+    }
+
+
     public SpecificationLoader(
             final IsisConfiguration configuration,
             final ProgrammingModel programmingModel,
@@ -118,6 +133,8 @@ public class SpecificationLoader implements ApplicationScopedComponent {
         this.postProcessor = new PostProcessor(programmingModel, servicesInjector);
 
         this.layoutMetadataReaders = layoutMetadataReaders;
+
+        this.state = State.NOT_INITIALIZED;
     }
 
     @Override
@@ -132,7 +149,7 @@ public class SpecificationLoader implements ApplicationScopedComponent {
 
     //region > init
 
-    private boolean initialized = false;
+    private State state;
 
     /**
      * Initializes and wires up, and primes the cache based on any service
@@ -152,34 +169,78 @@ public class SpecificationLoader implements ApplicationScopedComponent {
         }
 
         // initialize subcomponents
-        programmingModel.init();
+        this.programmingModel.init();
         facetProcessor.init();
+
+        ProgrammingModel programmingModelForObjectSpecId = new ProgrammingModelForObjectSpecIdFacet(configuration);
+        facetProcessorObjectSpecId = new FacetProcessor(programmingModelForObjectSpecId) {
+            @Override
+            public void injectDependenciesInto(final FacetFactory factory) {
+                // no-op... otherwise hit an exception in the other thread, but don't (yet) know why.
+            }
+        };
+        programmingModelForObjectSpecId.init();
+        facetProcessorObjectSpecId.init();
+
         postProcessor.init();
         metaModelValidator.init(this);
 
+
+        state = State.CACHING;
+
         loadSpecificationsForServices();
         loadSpecificationsForMixins();
         cacheBySpecId();
 
-        initialized = true;
+        state = State.INTROSPECTING;
+
+        final Collection<ObjectSpecification> objectSpecifications = allSpecifications();
+
+        final List<Callable<Object>> callables = Lists.newArrayList();
+        for (final ObjectSpecification specification : objectSpecifications) {
+            Callable<Object> callable = new Callable<Object>() {
+                @Override
+                public Object call() {
+                    introspectIfRequired(specification);
+                    return null;
+                }
+            };
+            callables.add(callable);
+        }
+        List<Future<Object>> futures = ThreadPoolSupport.invokeAll(callables);
+        ThreadPoolSupport.joinGatherFailures(futures);
+
     }
 
     private void loadSpecificationsForServices() {
-        for (final Class<?> serviceClass : allServiceClasses()) {
+        final Properties metadataProperties = new Properties();
+
+        List<Class<?>> classes = allServiceClasses();
+        for (final Class<?> serviceClass : classes) {
             final DomainService domainService = serviceClass.getAnnotation(DomainService.class);
             final NatureOfService nature = domainService != null ? domainService.nature() : NatureOfService.DOMAIN;
             // will 'markAsService'
-            internalLoadSpecification(serviceClass, nature);
+            ObjectSpecification objectSpecification = internalLoadSpecification(serviceClass, nature);
+
+            facetProcessorObjectSpecId.process(
+                    serviceClass, metadataProperties,
+                    MethodRemoverConstants.NULL, objectSpecification);
         }
     }
 
     private void loadSpecificationsForMixins() {
+        final Properties metadataProperties = new Properties();
+
         final Set<Class<?>> mixinTypes = AppManifest.Registry.instance().getMixinTypes();
         if(mixinTypes == null) {
             return;
         }
         for (final Class<?> mixinType : mixinTypes) {
-            internalLoadSpecification(mixinType);
+            ObjectSpecification objectSpecification = internalLoadSpecification(mixinType);
+            facetProcessorObjectSpecId.process(
+                    mixinType, metadataProperties,
+                    MethodRemoverConstants.NULL, objectSpecification);
+
         }
     }
 
@@ -196,10 +257,6 @@ public class SpecificationLoader implements ApplicationScopedComponent {
         cache.setCacheBySpecId(specById);
     }
 
-    @Programmatic
-    public boolean isInitialized() {
-        return initialized;
-    }
 
 
     //endregion
@@ -210,7 +267,7 @@ public class SpecificationLoader implements ApplicationScopedComponent {
     public void shutdown() {
         LOG.info("shutting down {}", this);
 
-        initialized = false;
+        state = State.NOT_INITIALIZED;
 
         cache.clear();
     }
@@ -437,6 +494,10 @@ public class SpecificationLoader implements ApplicationScopedComponent {
      */
     private ObjectSpecification introspectIfRequired(final ObjectSpecification spec) {
 
+        if(state != State.INTROSPECTING) {
+            return spec;
+        }
+
         final ObjectSpecificationAbstract specSpi = (ObjectSpecificationAbstract)spec;
         final ObjectSpecificationAbstract.IntrospectionState introspectionState = specSpi.getIntrospectionState();
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
index 65d2ff3..ca56568 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
@@ -103,7 +103,6 @@ public class ObjectSpecificationDefault extends ObjectSpecificationAbstract impl
     }
 
 
-
     //endregion
 
     //region > introspectTypeHierarchyAndMembers
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/runtime/threadpool/ThreadPoolSupport.java b/core/metamodel/src/main/java/org/apache/isis/core/runtime/threadpool/ThreadPoolSupport.java
index 09c9fe7..c131f18 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/runtime/threadpool/ThreadPoolSupport.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/runtime/threadpool/ThreadPoolSupport.java
@@ -26,6 +26,7 @@ import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.RejectedExecutionHandler;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
@@ -50,7 +51,7 @@ public final class ThreadPoolSupport {
         final int maximumPoolSize = Runtime.getRuntime().availableProcessors();
         final int keepAliveTimeSecs = 5;
 
-        final int queueCapacity = 25;
+        final int queueCapacity = 200;
         final BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(queueCapacity);
 
         executor = new ThreadPoolExecutor(
@@ -63,7 +64,14 @@ public final class ThreadPoolSupport {
                     public Thread newThread(final Runnable r) {
                         return new Thread(group, r);
                     }
-                });
+                }, new RejectedExecutionHandler() {
+            @Override
+            public void rejectedExecution(final Runnable r, final ThreadPoolExecutor executor) {
+                int i;
+                i=1;
+
+            }
+        });
     }
 
     public static List<Object> join(final List<Future<Object>> futures) {
@@ -75,7 +83,38 @@ public final class ThreadPoolSupport {
         try{
             final List<Object> returnValues = Lists.newArrayList();
             for (Future<Object> future : futures) {
-                returnValues.add(join(future));
+                Object result;
+                try {
+                    result = future.get();
+                } catch (InterruptedException | ExecutionException e) {
+                    // ignore
+                    result = null;
+                }
+                returnValues.add(result);
+            }
+            return returnValues;
+        } finally {
+            final long t1 = System.currentTimeMillis();
+            LOG.info("join'ing {} tasks: waited {} milliseconds ", futures.size(), (t1-t0));
+        }
+    }
+
+    public static List<Object> joinGatherFailures(final List<Future<Object>> futures) {
+        if (futures == null) {
+            return null;
+        }
+
+        final long t0 = System.currentTimeMillis();
+        try{
+            final List<Object> returnValues = Lists.newArrayList();
+            for (Future<Object> future : futures) {
+                final Object result;
+                try {
+                    result = future.get();
+                } catch (InterruptedException | ExecutionException e) {
+                    throw new RuntimeException(e);
+                }
+                returnValues.add(result);
             }
             return returnValues;
         } finally {
@@ -89,8 +128,8 @@ public final class ThreadPoolSupport {
             return future.get();
         } catch (InterruptedException | ExecutionException e) {
             // ignore
+            return null;
         }
-        return null;
     }
 
     public static List<Future<Object>> invokeAll(final List<Callable<Object>> callables) {
diff --git a/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelForObjectSpecIdFacet.java b/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelForObjectSpecIdFacet.java
new file mode 100644
index 0000000..61f08a1
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelForObjectSpecIdFacet.java
@@ -0,0 +1,45 @@
+/* Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License. */
+
+package org.apache.isis.progmodels.dflt;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.isis.core.commons.config.IsisConfiguration;
+import org.apache.isis.core.metamodel.facets.object.objectspecid.classname.ObjectSpecIdFacetDerivedFromClassNameFactory;
+import org.apache.isis.core.metamodel.progmodel.ObjectSpecificationPostProcessor;
+import org.apache.isis.core.metamodel.progmodel.ProgrammingModelAbstract;
+
+public final class ProgrammingModelForObjectSpecIdFacet extends ProgrammingModelAbstract {
+
+    public ProgrammingModelForObjectSpecIdFacet(final IsisConfiguration configuration) {
+        this(DeprecatedPolicy.parse(configuration));
+    }
+
+    public ProgrammingModelForObjectSpecIdFacet(final DeprecatedPolicy deprecatedPolicy) {
+        super(deprecatedPolicy);
+
+        addFactory(new ObjectSpecIdFacetDerivedFromClassNameFactory());
+    }
+
+    @Override
+    public List<ObjectSpecificationPostProcessor> getPostProcessors() {
+        return Collections.emptyList();
+    }
+
+}
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/session/IsisSessionFactoryBuilder.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/session/IsisSessionFactoryBuilder.java
index 72d8ef2..9aa7097 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/session/IsisSessionFactoryBuilder.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/session/IsisSessionFactoryBuilder.java
@@ -221,8 +221,7 @@ public class IsisSessionFactoryBuilder {
                     }
             );
 
-            ThreadPoolSupport.join(futures);
-
+            ThreadPoolSupport.joinGatherFailures(futures);
 
             persistenceSessionFactory.catalogNamedQueries(specificationLoader);