Repository: camel Updated Branches: refs/heads/camel-2.16.x 63f851c29 -> c7ef72a56 refs/heads/camel-2.17.x 2207aafb6 -> be70180be refs/heads/master 40cda4711 -> e3890695b
CAMEL-10048: Fixed memory leak in routing slip. Thanks to Arseniy Tashoyan for the patch. Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/e3890695 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/e3890695 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/e3890695 Branch: refs/heads/master Commit: e3890695b8cb92dff1d14b38f2876ee925d9acff Parents: 40cda47 Author: Claus Ibsen <davscl...@apache.org> Authored: Sun Jun 12 11:08:03 2016 +0200 Committer: Claus Ibsen <davscl...@apache.org> Committed: Sun Jun 12 11:10:08 2016 +0200 ---------------------------------------------------------------------- .../util/AsyncProcessorConverterHelper.java | 20 ++++- .../camel/issues/RoutingSlipMemoryLeakTest.java | 80 ++++++++++++++++++++ 2 files changed, 99 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/e3890695/camel-core/src/main/java/org/apache/camel/util/AsyncProcessorConverterHelper.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/util/AsyncProcessorConverterHelper.java b/camel-core/src/main/java/org/apache/camel/util/AsyncProcessorConverterHelper.java index a48e037..6b1862e 100644 --- a/camel-core/src/main/java/org/apache/camel/util/AsyncProcessorConverterHelper.java +++ b/camel-core/src/main/java/org/apache/camel/util/AsyncProcessorConverterHelper.java @@ -45,7 +45,7 @@ public final class AsyncProcessorConverterHelper { * It is important that this implements {@link DelegateProcessor} */ private static final class ProcessorToAsyncProcessorBridge implements DelegateProcessor, AsyncProcessor, Navigate<Processor>, Service { - protected Processor processor; + protected final Processor processor; private ProcessorToAsyncProcessorBridge(Processor processor) { this.processor = processor; @@ -113,6 +113,24 @@ public final class AsyncProcessorConverterHelper { public Processor getProcessor() { return processor; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + ProcessorToAsyncProcessorBridge that = (ProcessorToAsyncProcessorBridge) o; + return processor.equals(that.processor); + } + + @Override + public int hashCode() { + return processor.hashCode(); + } } public static AsyncProcessor convert(Processor value) { http://git-wip-us.apache.org/repos/asf/camel/blob/e3890695/camel-core/src/test/java/org/apache/camel/issues/RoutingSlipMemoryLeakTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/issues/RoutingSlipMemoryLeakTest.java b/camel-core/src/test/java/org/apache/camel/issues/RoutingSlipMemoryLeakTest.java new file mode 100644 index 0000000..7ead2b3 --- /dev/null +++ b/camel-core/src/test/java/org/apache/camel/issues/RoutingSlipMemoryLeakTest.java @@ -0,0 +1,80 @@ +/** + * 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.issues; + +import java.lang.reflect.Field; +import java.util.Map; + +import org.apache.camel.ContextTestSupport; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.processor.RoutingSlip; + +public class RoutingSlipMemoryLeakTest extends ContextTestSupport { + + @Override + protected void setUp() throws Exception { + deleteDirectory("target/output"); + super.setUp(); + } + + /** + * Reproducer for the memory leak: CAMEL-10048 + */ + public void testMemoryLeakInExceptionHandlerCaching() throws Exception { + int messageCount = 100; + for (int i = 0; i < messageCount; i++) { + template.sendBody("direct:start", "message " + i); + } + RoutingSlip routingSlip = context.getProcessor("memory-leak", RoutingSlip.class); + Map errorHandlers = getRoutingSlipErrorHandlers(routingSlip); + assertEquals("Error handlers cache must contain only one value", 1, errorHandlers.size()); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start") + .routingSlip(method(SlipProvider.class)).id("memory-leak"); + } + }; + } + + private Map<?, ?> getRoutingSlipErrorHandlers(RoutingSlip routingSlip) throws Exception { + Field errorHandlersField = routingSlip.getClass().getDeclaredField("errorHandlers"); + errorHandlersField.setAccessible(true); + Map errorHandlers = (Map) errorHandlersField.get(routingSlip); + return errorHandlers; + } + + public static class SlipProvider { + + public String computeSlip(String body) { + /* + * It is important to have a processor here, that does not extend + * AsyncProcessor. Only in this case + * AsyncProcessorConverterHelper.convert() creates a new object, + * thus leading to a memory leak. For example, if you replace file + * endpoint with mock endpoint, then everything goes fine, because + * MockEndpoint.createProducer() creates an implementation of + * AsyncProcessor. + */ + return "file:target/output"; + } + } +} \ No newline at end of file