This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch camel-4.0.x in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/camel-4.0.x by this push: new edb7f9be4d6 Optimize EndpointHelper.matchEndpoint (#11723) edb7f9be4d6 is described below commit edb7f9be4d6d59393b5bbd4a4e1fa448a3994715 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Sun Oct 15 09:14:18 2023 +0200 Optimize EndpointHelper.matchEndpoint (#11723) * CAMEL-19987: camel-core - Optimize EndpointHelper.matchEndpoint * CAMEL-19987: camel-core - Optimize EndpointHelper.matchEndpoint to avoid regexp in fast-mode * CAMEL-19987: camel-core - Optimize EndpointHelper.matchEndpoint to avoid regexp in fast-mode --- .../camel/impl/engine/AbstractCamelContext.java | 15 +++++- .../camel/impl/DefaultEndpointRegistryTest.java | 55 ++++++++++++++++++++++ .../org/apache/camel/support/EndpointHelper.java | 33 +++++++++---- .../org/apache/camel/support/PatternHelper.java | 2 +- 4 files changed, 93 insertions(+), 12 deletions(-) diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java index c92234628a6..8ad6d6e3d72 100644 --- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java +++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java @@ -699,7 +699,20 @@ public abstract class AbstractCamelContext extends BaseService @Override public void removeEndpoint(Endpoint endpoint) throws Exception { - removeEndpoints(endpoint.getEndpointUri()); + // optimize as uri on endpoint is already normalized + String uri = endpoint.getEndpointUri(); + NormalizedUri key = NormalizedUri.newNormalizedUri(uri, true); + Endpoint oldEndpoint = endpoints.remove(key); + if (oldEndpoint != null) { + try { + stopServices(oldEndpoint); + } catch (Exception e) { + LOG.warn("Error stopping endpoint {}. This exception will be ignored.", oldEndpoint, e); + } + for (LifecycleStrategy strategy : lifecycleStrategies) { + strategy.onEndpointRemove(oldEndpoint); + } + } } @Override diff --git a/core/camel-core/src/test/java/org/apache/camel/impl/DefaultEndpointRegistryTest.java b/core/camel-core/src/test/java/org/apache/camel/impl/DefaultEndpointRegistryTest.java index 4bcae075a55..23341b587c2 100644 --- a/core/camel-core/src/test/java/org/apache/camel/impl/DefaultEndpointRegistryTest.java +++ b/core/camel-core/src/test/java/org/apache/camel/impl/DefaultEndpointRegistryTest.java @@ -19,7 +19,10 @@ package org.apache.camel.impl; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; +import org.apache.camel.Endpoint; +import org.apache.camel.FluentProducerTemplate; import org.apache.camel.ProducerTemplate; import org.apache.camel.ServiceStatus; import org.apache.camel.builder.RouteBuilder; @@ -27,12 +30,64 @@ import org.apache.camel.impl.engine.DefaultEndpointRegistry; import org.apache.camel.impl.engine.SimpleCamelContext; import org.apache.camel.spi.EndpointRegistry; import org.apache.camel.support.NormalizedUri; +import org.awaitility.Awaitility; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertTrue; public class DefaultEndpointRegistryTest { + @Test + public void testRemoveEndpoint() throws Exception { + DefaultCamelContext ctx = new DefaultCamelContext(); + ctx.start(); + + ctx.getEndpoint("direct:one"); + Endpoint e = ctx.getEndpoint("direct:two"); + ctx.getEndpoint("direct:three"); + + Assertions.assertEquals(3, ctx.getEndpoints().size()); + ctx.removeEndpoint(e); + Assertions.assertEquals(2, ctx.getEndpoints().size()); + } + + @Test + public void testRemoveEndpointToD() throws Exception { + DefaultCamelContext ctx = new DefaultCamelContext(); + ctx.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start") + .toD().cacheSize(10).uri("mock:${header.foo}"); + } + }); + final AtomicInteger cnt = new AtomicInteger(); + ctx.addLifecycleStrategy(new DummyLifecycleStrategy() { + @Override + public void onEndpointRemove(Endpoint endpoint) { + cnt.incrementAndGet(); + } + }); + ctx.start(); + + Assertions.assertEquals(0, cnt.get()); + Assertions.assertEquals(1, ctx.getEndpoints().size()); + + FluentProducerTemplate template = ctx.createFluentProducerTemplate(); + for (int i = 0; i < 100; i++) { + template.withBody("Hello").withHeader("foo", "" + i).to("direct:start").send(); + } + + Awaitility.await().untilAsserted(() -> { + Assertions.assertEquals(11, ctx.getEndpoints().size()); + }); + + Assertions.assertEquals(90, cnt.get()); + + ctx.stop(); + } + @Test public void testMigration() throws Exception { DefaultCamelContext ctx = new DefaultCamelContext(); diff --git a/core/camel-support/src/main/java/org/apache/camel/support/EndpointHelper.java b/core/camel-support/src/main/java/org/apache/camel/support/EndpointHelper.java index c37820caa3f..4a6449eec02 100644 --- a/core/camel-support/src/main/java/org/apache/camel/support/EndpointHelper.java +++ b/core/camel-support/src/main/java/org/apache/camel/support/EndpointHelper.java @@ -221,7 +221,7 @@ public final class EndpointHelper { * @param context the Camel context, if <tt>null</tt> then property placeholder resolution is skipped. * @param uri the endpoint uri * @param pattern a pattern to match - * @return <tt>true</tt> if match, <tt>false</tt> otherwise. + * @return <tt>true</tt> if matched, <tt>false</tt> otherwise. */ public static boolean matchEndpoint(CamelContext context, String uri, String pattern) { if (context != null) { @@ -235,18 +235,31 @@ public final class EndpointHelper { // normalize uri so we can do endpoint hits with minor mistakes and parameters is not in the same order uri = normalizeEndpointUri(uri); - // we need to test with and without scheme separators (//) - boolean match = PatternHelper.matchPattern(toggleUriSchemeSeparators(uri), pattern); - match |= PatternHelper.matchPattern(uri, pattern); - if (!match && pattern != null && pattern.contains("?")) { - // try normalizing the pattern as a uri for exact matching, so parameters are ordered the same as in the endpoint uri + // do fast matching without regexp first + boolean match = doMatchEndpoint(uri, pattern, false); + if (!match) { + // this is slower as pattern is compiled as regexp + match = doMatchEndpoint(uri, pattern, true); + } + return match; + } + + private static boolean doMatchEndpoint(String uri, String pattern, boolean regexp) { + String toggleUri = null; + boolean match = regexp ? PatternHelper.matchRegex(uri, pattern) : PatternHelper.matchPattern(uri, pattern); + if (!match) { + toggleUri = toggleUriSchemeSeparators(uri); + match = regexp ? PatternHelper.matchRegex(toggleUri, pattern) : PatternHelper.matchPattern(toggleUri, pattern); + } + if (!match && !regexp && pattern != null && pattern.contains("?")) { + // this is only need to be done once (in fast mode when regexp=false) + // try normalizing the pattern as an uri for exact matching, so parameters are ordered the same as in the endpoint uri try { pattern = URISupport.normalizeUri(pattern); // try both with and without scheme separators (//) - match = toggleUriSchemeSeparators(uri).equalsIgnoreCase(pattern); - return match || uri.equalsIgnoreCase(pattern); + return uri.equalsIgnoreCase(pattern) || toggleUri.equalsIgnoreCase(pattern); } catch (URISyntaxException e) { - //Can't normalize and original match failed + // cannot normalize and original match failed return false; } catch (Exception e) { throw new ResolveEndpointFailedException(uri, e); @@ -278,7 +291,7 @@ public final class EndpointHelper { * Is the given parameter a reference parameter (starting with a # char) * * @param parameter the parameter - * @return <tt>true</tt> if its a reference parameter + * @return <tt>true</tt> if it's a reference parameter */ public static boolean isReferenceParameter(String parameter) { return parameter != null && parameter.trim().startsWith("#") && parameter.trim().length() > 1; diff --git a/core/camel-support/src/main/java/org/apache/camel/support/PatternHelper.java b/core/camel-support/src/main/java/org/apache/camel/support/PatternHelper.java index e490f7e6a51..a716b860ea5 100644 --- a/core/camel-support/src/main/java/org/apache/camel/support/PatternHelper.java +++ b/core/camel-support/src/main/java/org/apache/camel/support/PatternHelper.java @@ -116,7 +116,7 @@ public final class PatternHelper { * @param pattern a pattern to match * @return <tt>true</tt> if match, <tt>false</tt> otherwise. */ - private static boolean matchRegex(String name, String pattern) { + public static boolean matchRegex(String name, String pattern) { // match by regular expression try { Pattern compiled = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);