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 2012/02/15 20:04:10 UTC
svn commit: r1244644 - in /camel/trunk/camel-core/src:
main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java
test/java/org/apache/camel/issues/MyCamelBean.java
test/java/org/apache/camel/issues/TypeConverterConcurrencyIssueTest.java
Author: davsclaus
Date: Wed Feb 15 19:04:10 2012
New Revision: 1244644
URL: http://svn.apache.org/viewvc?rev=1244644&view=rev
Log:
CAMEL-5002: Improved type converter lookup to avoid synchronization.
Added:
camel/trunk/camel-core/src/test/java/org/apache/camel/issues/MyCamelBean.java
camel/trunk/camel-core/src/test/java/org/apache/camel/issues/TypeConverterConcurrencyIssueTest.java
Modified:
camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java
Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java?rev=1244644&r1=1244643&r2=1244644&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java Wed Feb 15 19:04:10 2012
@@ -52,7 +52,7 @@ import org.slf4j.LoggerFactory;
*/
public abstract class BaseTypeConverterRegistry extends ServiceSupport implements TypeConverter, TypeConverterRegistry {
protected final transient Logger log = LoggerFactory.getLogger(getClass());
- protected final Map<TypeMapping, TypeConverter> typeMappings = new ConcurrentHashMap<TypeMapping, TypeConverter>();
+ protected final ConcurrentHashMap<TypeMapping, TypeConverter> typeMappings = new ConcurrentHashMap<TypeMapping, TypeConverter>();
protected final Map<TypeMapping, TypeMapping> misses = new ConcurrentHashMap<TypeMapping, TypeMapping>();
protected final List<TypeConverterLoader> typeConverterLoaders = new ArrayList<TypeConverterLoader>();
protected final List<FallbackTypeConverter> fallbackConverters = new ArrayList<FallbackTypeConverter>();
@@ -237,18 +237,16 @@ public abstract class BaseTypeConverterR
public void addTypeConverter(Class<?> toType, Class<?> fromType, TypeConverter typeConverter) {
log.trace("Adding type converter: {}", typeConverter);
TypeMapping key = new TypeMapping(toType, fromType);
- synchronized (typeMappings) {
- TypeConverter converter = typeMappings.get(key);
- // only override it if its different
- // as race conditions can lead to many threads trying to promote the same fallback converter
- if (typeConverter != converter) {
- if (converter != null) {
- log.warn("Overriding type converter from: " + converter + " to: " + typeConverter);
- }
- typeMappings.put(key, typeConverter);
- // remove any previous misses, as we added the new type converter
- misses.remove(key);
+ TypeConverter converter = typeMappings.get(key);
+ // only override it if its different
+ // as race conditions can lead to many threads trying to promote the same fallback converter
+ if (typeConverter != converter) {
+ if (converter != null) {
+ log.warn("Overriding type converter from: " + converter + " to: " + typeConverter);
}
+ typeMappings.put(key, typeConverter);
+ // remove any previous misses, as we added the new type converter
+ misses.remove(key);
}
}
@@ -281,22 +279,18 @@ public abstract class BaseTypeConverterR
public Set<Class<?>> getFromClassMappings() {
Set<Class<?>> answer = new HashSet<Class<?>>();
- synchronized (typeMappings) {
- for (TypeMapping mapping : typeMappings.keySet()) {
- answer.add(mapping.getFromType());
- }
+ for (TypeMapping mapping : typeMappings.keySet()) {
+ answer.add(mapping.getFromType());
}
return answer;
}
public Map<Class<?>, TypeConverter> getToClassMappings(Class<?> fromClass) {
Map<Class<?>, TypeConverter> answer = new HashMap<Class<?>, TypeConverter>();
- synchronized (typeMappings) {
- for (Map.Entry<TypeMapping, TypeConverter> entry : typeMappings.entrySet()) {
- TypeMapping mapping = entry.getKey();
- if (mapping.isApplicable(fromClass)) {
- answer.put(mapping.getToType(), entry.getValue());
- }
+ for (Map.Entry<TypeMapping, TypeConverter> entry : typeMappings.entrySet()) {
+ TypeMapping mapping = entry.getKey();
+ if (mapping.isApplicable(fromClass)) {
+ answer.put(mapping.getToType(), entry.getValue());
}
}
return answer;
@@ -312,14 +306,12 @@ public abstract class BaseTypeConverterR
fromType = value.getClass();
}
TypeMapping key = new TypeMapping(toType, fromType);
- TypeConverter converter;
- synchronized (typeMappings) {
- converter = typeMappings.get(key);
- if (converter == null) {
- converter = lookup(toType, fromType);
- if (converter != null) {
- typeMappings.put(key, converter);
- }
+ TypeConverter converter = typeMappings.get(key);
+ if (converter == null) {
+ // converter not found, try to lookup then
+ converter = lookup(toType, fromType);
+ if (converter != null) {
+ typeMappings.putIfAbsent(key, converter);
}
}
return converter;
Added: camel/trunk/camel-core/src/test/java/org/apache/camel/issues/MyCamelBean.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/issues/MyCamelBean.java?rev=1244644&view=auto
==============================================================================
--- camel/trunk/camel-core/src/test/java/org/apache/camel/issues/MyCamelBean.java (added)
+++ camel/trunk/camel-core/src/test/java/org/apache/camel/issues/MyCamelBean.java Wed Feb 15 19:04:10 2012
@@ -0,0 +1,42 @@
+/**
+ * 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;
+
+/**
+ *
+ */
+public class MyCamelBean {
+
+ private int id;
+ private String name;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
Added: camel/trunk/camel-core/src/test/java/org/apache/camel/issues/TypeConverterConcurrencyIssueTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/issues/TypeConverterConcurrencyIssueTest.java?rev=1244644&view=auto
==============================================================================
--- camel/trunk/camel-core/src/test/java/org/apache/camel/issues/TypeConverterConcurrencyIssueTest.java (added)
+++ camel/trunk/camel-core/src/test/java/org/apache/camel/issues/TypeConverterConcurrencyIssueTest.java Wed Feb 15 19:04:10 2012
@@ -0,0 +1,67 @@
+/**
+ * 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.Method;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.impl.converter.StaticMethodTypeConverter;
+import org.apache.camel.util.StopWatch;
+
+/**
+ * Testing for CAMEL-5002
+ */
+public class TypeConverterConcurrencyIssueTest extends ContextTestSupport {
+
+ private int size = 100 * 1000;
+
+ public void testTypeConverter() throws Exception {
+ // add as type converter
+ Method method = TypeConverterConcurrencyIssueTest.class.getMethod("toMyCamelBean", String.class);
+ assertNotNull(method);
+ context.getTypeConverterRegistry().addTypeConverter(MyCamelBean.class, String.class, new StaticMethodTypeConverter(method));
+
+ ExecutorService pool = context.getExecutorServiceManager().newThreadPool(this, "test", 50, 50);
+ final CountDownLatch latch = new CountDownLatch(size);
+
+ StopWatch watch = new StopWatch();
+ for (int i = 0; i < size; i++) {
+ pool.submit(new Runnable() {
+ @Override
+ public void run() {
+ MyCamelBean bean = context.getTypeConverter().convertTo(MyCamelBean.class, "1;MyCamel");
+ latch.countDown();
+ }
+ });
+ }
+
+ assertTrue(latch.await(1, TimeUnit.MINUTES));
+ log.info("Took " + watch.stop() + " millis to convert " + size + " objects");
+ }
+
+ public static MyCamelBean toMyCamelBean(String body) {
+ MyCamelBean bean = new MyCamelBean();
+ String[] data = body.split(";");
+ bean.setId(Integer.parseInt(data[0]));
+ bean.setName(data[1]);
+ return bean;
+ }
+
+}