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 2023/10/15 07:15:01 UTC
[camel] branch camel-4.0.x updated: Optimize EndpointHelper.matchEndpoint (#11723)
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 <cl...@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);