You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2017/07/05 07:28:35 UTC

[2/8] camel git commit: CAMEL-11321: Start Camel faster by letting LRUCache warmup concurrently as that takes up 150 millis or more.

CAMEL-11321: Start Camel faster by letting LRUCache warmup concurrently as that takes up 150 millis or more.


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/f8e68bac
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/f8e68bac
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/f8e68bac

Branch: refs/heads/master
Commit: f8e68bac676d9a1a43f1f2744aa467cba77ec169
Parents: f647c22
Author: Claus Ibsen <da...@apache.org>
Authored: Tue Jul 4 15:46:17 2017 +0200
Committer: Claus Ibsen <da...@apache.org>
Committed: Wed Jul 5 09:28:22 2017 +0200

----------------------------------------------------------------------
 .../apache/camel/impl/DefaultCamelContext.java  | 13 +++-
 .../impl/DefaultPackageScanClassResolver.java   |  4 +-
 .../camel/impl/ProvisionalEndpointRegistry.java | 74 ++++++++++++++++++++
 .../management/DefaultManagementAgent.java      | 10 ++-
 .../DefaultManagementMBeanAssembler.java        | 13 +++-
 .../camel/management/MBeanInfoAssembler.java    |  6 +-
 .../org/apache/camel/util/LRUCacheFactory.java  | 59 ++++++++++++++++
 .../org/apache/camel/ContextTestSupport.java    |  2 +
 8 files changed, 173 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/f8e68bac/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java b/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
index ef50425..3ebad6d 100644
--- a/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
+++ b/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
@@ -178,6 +178,7 @@ import org.apache.camel.util.EventHelper;
 import org.apache.camel.util.IOHelper;
 import org.apache.camel.util.IntrospectionSupport;
 import org.apache.camel.util.JsonSchemaHelper;
+import org.apache.camel.util.LRUCacheFactory;
 import org.apache.camel.util.LoadPropertiesException;
 import org.apache.camel.util.ObjectHelper;
 import org.apache.camel.util.OrderedComparator;
@@ -316,10 +317,18 @@ public class DefaultCamelContext extends ServiceSupport implements ModelCamelCon
      * Use one of the other constructors to force use an explicit registry / JNDI.
      */
     public DefaultCamelContext() {
+        boolean warmUp = "true".equalsIgnoreCase(System.getProperty("CamelWarmUpLRUCacheFactory", "true"));
+        if (warmUp) {
+            // warm-up LRUCache which happens in a background test, which can speedup starting Camel
+            // as the warm-up can run concurrently with starting up Camel and the runtime container Camel may be running inside
+            LRUCacheFactory.warmUp();
+        }
+
         this.executorServiceManager = new DefaultExecutorServiceManager(this);
 
-        // create endpoint registry at first since end users may access endpoints before CamelContext is started
-        this.endpoints = new DefaultEndpointRegistry(this);
+        // create a provisional (temporary) endpoint registry at first since end users may access endpoints before CamelContext is started
+        // we will later transfer the endpoints to the actual DefaultEndpointRegistry later, but we do this to starup Camel faster.
+        this.endpoints = new ProvisionalEndpointRegistry();
 
         // add the defer service startup listener
         this.startupListeners.add(deferStartupListener);

http://git-wip-us.apache.org/repos/asf/camel/blob/f8e68bac/camel-core/src/main/java/org/apache/camel/impl/DefaultPackageScanClassResolver.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/impl/DefaultPackageScanClassResolver.java b/camel-core/src/main/java/org/apache/camel/impl/DefaultPackageScanClassResolver.java
index a9074f8..13dfa3d 100644
--- a/camel-core/src/main/java/org/apache/camel/impl/DefaultPackageScanClassResolver.java
+++ b/camel-core/src/main/java/org/apache/camel/impl/DefaultPackageScanClassResolver.java
@@ -47,7 +47,7 @@ import org.apache.camel.spi.PackageScanClassResolver;
 import org.apache.camel.spi.PackageScanFilter;
 import org.apache.camel.support.ServiceSupport;
 import org.apache.camel.util.IOHelper;
-import org.apache.camel.util.LRUSoftCache;
+import org.apache.camel.util.LRUCacheFactory;
 import org.apache.camel.util.ObjectHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -510,7 +510,7 @@ public class DefaultPackageScanClassResolver extends ServiceSupport implements P
     protected void doStart() throws Exception {
         if (jarCache == null) {
             // use a JAR cache to speed up scanning JARs, but let it be soft referenced so it can claim the data when memory is needed
-            jarCache = new LRUSoftCache<String, List<String>>(1000);
+            jarCache = LRUCacheFactory.newLRUCache(1000);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/camel/blob/f8e68bac/camel-core/src/main/java/org/apache/camel/impl/ProvisionalEndpointRegistry.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/impl/ProvisionalEndpointRegistry.java b/camel-core/src/main/java/org/apache/camel/impl/ProvisionalEndpointRegistry.java
new file mode 100644
index 0000000..0600066
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/impl/ProvisionalEndpointRegistry.java
@@ -0,0 +1,74 @@
+/**
+ * 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.camel.impl;
+
+import java.util.HashMap;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.spi.EndpointRegistry;
+
+/**
+ * A provisional (temporary) {@link EndpointRegistry} that is only used during startup of Apache Camel to
+ * make starting Camel faster while {@link org.apache.camel.util.LRUCacheFactory} is warming up etc.
+ */
+class ProvisionalEndpointRegistry extends HashMap<EndpointKey, Endpoint> implements EndpointRegistry<EndpointKey> {
+
+    @Override
+    public void start() throws Exception {
+        // noop
+    }
+
+    @Override
+    public void stop() throws Exception {
+        // noop
+    }
+
+    @Override
+    public int staticSize() {
+        return 0;
+    }
+
+    @Override
+    public int dynamicSize() {
+        return 0;
+    }
+
+    @Override
+    public int getMaximumCacheSize() {
+        return 0;
+    }
+
+    @Override
+    public void purge() {
+        // noop
+    }
+
+    @Override
+    public boolean isStatic(String key) {
+        return false;
+    }
+
+    @Override
+    public boolean isDynamic(String key) {
+        return false;
+    }
+
+    @Override
+    public void cleanUp() {
+        // noop
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/f8e68bac/camel-core/src/main/java/org/apache/camel/management/DefaultManagementAgent.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/management/DefaultManagementAgent.java b/camel-core/src/main/java/org/apache/camel/management/DefaultManagementAgent.java
index 7f6449b..d3f7280 100644
--- a/camel-core/src/main/java/org/apache/camel/management/DefaultManagementAgent.java
+++ b/camel-core/src/main/java/org/apache/camel/management/DefaultManagementAgent.java
@@ -49,6 +49,7 @@ import org.apache.camel.spi.ManagementMBeanAssembler;
 import org.apache.camel.support.ServiceSupport;
 import org.apache.camel.util.InetAddressUtil;
 import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.ServiceHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -66,6 +67,8 @@ public class DefaultManagementAgent extends ServiceSupport implements Management
 
     private CamelContext camelContext;
     private MBeanServer server;
+    private ManagementMBeanAssembler assembler;
+
     // need a name -> actual name mapping as some servers changes the names (such as WebSphere)
     private final ConcurrentMap<ObjectName, ObjectName> mbeansRegistered = new ConcurrentHashMap<ObjectName, ObjectName>();
     private JMXConnectorServer cs;
@@ -339,7 +342,6 @@ public class DefaultManagementAgent extends ServiceSupport implements Management
             registerMBeanWithServer(obj, name, forceRegistration);
         } catch (NotCompliantMBeanException e) {
             // If this is not a "normal" MBean, then try to deploy it using JMX annotations
-            ManagementMBeanAssembler assembler = camelContext.getManagementMBeanAssembler();
             ObjectHelper.notNull(assembler, "ManagementMBeanAssembler", camelContext);
             Object mbean = assembler.assemble(server, obj, name);
             if (mbean != null) {
@@ -386,6 +388,10 @@ public class DefaultManagementAgent extends ServiceSupport implements Management
             createMBeanServer();
         }
 
+        // ensure assembler is started
+        assembler = camelContext.getManagementMBeanAssembler();
+        ServiceHelper.startService(assembler);
+
         LOG.debug("Starting JMX agent on server: {}", getMBeanServer());
     }
 
@@ -432,6 +438,8 @@ public class DefaultManagementAgent extends ServiceSupport implements Management
                      + " exceptions caught while unregistering MBeans during stop operation."
                      + " See INFO log for details.");
         }
+
+        ServiceHelper.stopService(assembler);
     }
 
     private void registerMBeanWithServer(Object obj, ObjectName name, boolean forceRegistration)

http://git-wip-us.apache.org/repos/asf/camel/blob/f8e68bac/camel-core/src/main/java/org/apache/camel/management/DefaultManagementMBeanAssembler.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/management/DefaultManagementMBeanAssembler.java b/camel-core/src/main/java/org/apache/camel/management/DefaultManagementMBeanAssembler.java
index a28bcbb..dc8f970 100644
--- a/camel-core/src/main/java/org/apache/camel/management/DefaultManagementMBeanAssembler.java
+++ b/camel-core/src/main/java/org/apache/camel/management/DefaultManagementMBeanAssembler.java
@@ -29,7 +29,9 @@ import org.apache.camel.api.management.ManagedInstance;
 import org.apache.camel.api.management.ManagedResource;
 import org.apache.camel.api.management.NotificationSenderAware;
 import org.apache.camel.spi.ManagementMBeanAssembler;
+import org.apache.camel.support.ServiceSupport;
 import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.ServiceHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -40,7 +42,7 @@ import org.slf4j.LoggerFactory;
  *
  * @version 
  */
-public class DefaultManagementMBeanAssembler implements ManagementMBeanAssembler {
+public class DefaultManagementMBeanAssembler extends ServiceSupport implements ManagementMBeanAssembler {
     private static final Logger LOG = LoggerFactory.getLogger(DefaultManagementMBeanAssembler.class);
     protected final MBeanInfoAssembler assembler;
     protected final CamelContext camelContext;
@@ -114,4 +116,13 @@ public class DefaultManagementMBeanAssembler implements ManagementMBeanAssembler
         return mbean;
     }
 
+    @Override
+    protected void doStart() throws Exception {
+        ServiceHelper.startService(assembler);
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        ServiceHelper.stopService(assembler);
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/f8e68bac/camel-core/src/main/java/org/apache/camel/management/MBeanInfoAssembler.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/management/MBeanInfoAssembler.java b/camel-core/src/main/java/org/apache/camel/management/MBeanInfoAssembler.java
index 09cbf89..4dfb0b7 100644
--- a/camel-core/src/main/java/org/apache/camel/management/MBeanInfoAssembler.java
+++ b/camel-core/src/main/java/org/apache/camel/management/MBeanInfoAssembler.java
@@ -40,6 +40,7 @@ import org.apache.camel.api.management.ManagedOperation;
 import org.apache.camel.api.management.ManagedResource;
 import org.apache.camel.util.IntrospectionSupport;
 import org.apache.camel.util.LRUCache;
+import org.apache.camel.util.LRUCacheFactory;
 import org.apache.camel.util.LRUWeakCache;
 import org.apache.camel.util.ObjectHelper;
 import org.slf4j.Logger;
@@ -57,7 +58,7 @@ public class MBeanInfoAssembler implements Service {
     // use a cache to speedup gathering JMX MBeanInfo for known classes
     // use a weak cache as we dont want the cache to keep around as it reference classes
     // which could prevent classloader to unload classes if being referenced from this cache
-    private final LRUCache<Class<?>, MBeanAttributesAndOperations> cache = new LRUWeakCache<Class<?>, MBeanAttributesAndOperations>(1000);
+    private LRUCache<Class<?>, MBeanAttributesAndOperations> cache;
 
     public MBeanInfoAssembler() {
     }
@@ -67,8 +68,9 @@ public class MBeanInfoAssembler implements Service {
     }
 
     @Override
+    @SuppressWarnings("unchecked")
     public void start() throws Exception {
-        // noop
+        cache = LRUCacheFactory.newLRUWeakCache(1000);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/camel/blob/f8e68bac/camel-core/src/main/java/org/apache/camel/util/LRUCacheFactory.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/util/LRUCacheFactory.java b/camel-core/src/main/java/org/apache/camel/util/LRUCacheFactory.java
new file mode 100644
index 0000000..59b4620
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/util/LRUCacheFactory.java
@@ -0,0 +1,59 @@
+/**
+ * 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.camel.util;
+
+import org.apache.camel.util.concurrent.ThreadHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Factory to create {@link LRUCache} instances.
+ */
+public final class LRUCacheFactory {
+
+    // TODO: use LRUCacheFactory in other places to create the LRUCaches
+
+    private static final Logger LOG = LoggerFactory.getLogger(LRUCacheFactory.class);
+
+    private LRUCacheFactory() {
+    }
+
+    @SuppressWarnings("unchecked")
+    public static void warmUp() {
+        // create a dummy map in a separate thread to warmup the Caffeine cache
+        // as we want to do this as early as possible while creating CamelContext
+        // so when Camel is starting up its faster as the Caffeine cache has been initialized
+        Runnable warmup = () -> {
+            LOG.debug("Warming up LRUCache ...");
+            newLRUCache(16);
+            LOG.debug("Warming up LRUCache complete");
+        };
+
+        String threadName = ThreadHelper.resolveThreadName(null, "LRUCacheFactory");
+
+        Thread thread = new Thread(warmup, threadName);
+        thread.start();
+    }
+
+    public static LRUCache newLRUCache(int maximumCacheSize) {
+        return new LRUCache(maximumCacheSize);
+    }
+
+    public static LRUWeakCache newLRUWeakCache(int maximumCacheSize) {
+        return new LRUWeakCache(maximumCacheSize);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/f8e68bac/camel-core/src/test/java/org/apache/camel/ContextTestSupport.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/ContextTestSupport.java b/camel-core/src/test/java/org/apache/camel/ContextTestSupport.java
index e4544ce..8b9dfe4 100644
--- a/camel-core/src/test/java/org/apache/camel/ContextTestSupport.java
+++ b/camel-core/src/test/java/org/apache/camel/ContextTestSupport.java
@@ -83,6 +83,8 @@ public abstract class ContextTestSupport extends TestSupport {
     protected void setUp() throws Exception {
         // make SEDA testing faster
         System.setProperty("CamelSedaPollTimeout", "10");
+        // no need to warm-up when testing camel-core as that creates a new thread per CamelContext and Caffiene is initialized only once
+        System.setProperty("CamelWarmUpLRUCacheFactory", "false");
 
         if (!useJmx()) {
             disableJMX();