Author: davsclaus Date: Wed Jan 5 15:32:33 2011 New Revision: 1055489 URL: http://svn.apache.org/viewvc?rev=1055489&view=rev Log: CAMEL-3500: Headers on message is now using string interning for Camel keys, to reduce memory consumption.
Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/util/CaseInsensitiveMap.java camel/trunk/camel-core/src/test/java/org/apache/camel/util/CaseInsensitiveMapTest.java Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/util/CaseInsensitiveMap.java URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/util/CaseInsensitiveMap.java?rev=1055489&r1=1055488&r2=1055489&view=diff ============================================================================== --- camel/trunk/camel-core/src/main/java/org/apache/camel/util/CaseInsensitiveMap.java (original) +++ camel/trunk/camel-core/src/main/java/org/apache/camel/util/CaseInsensitiveMap.java Wed Jan 5 15:32:33 2011 @@ -65,7 +65,7 @@ public class CaseInsensitiveMap extends @Override public Object get(Object key) { - String s = key.toString().toLowerCase(); + String s = assembleKey(key); Object answer = super.get(s); if (answer == null) { // fallback to lookup by original key @@ -79,7 +79,7 @@ public class CaseInsensitiveMap extends public synchronized Object put(String key, Object value) { // invalidate views as we mutate entrySetView = null; - String s = key.toLowerCase(); + String s = assembleKey(key); originalKeys.put(s, key); return super.put(s, value); } @@ -101,7 +101,7 @@ public class CaseInsensitiveMap extends // invalidate views as we mutate entrySetView = null; - String s = key.toString().toLowerCase(); + String s = assembleKey(key); originalKeys.remove(s); return super.remove(s); } @@ -120,10 +120,20 @@ public class CaseInsensitiveMap extends return false; } - String s = key.toString().toLowerCase(); + String s = assembleKey(key); return super.containsKey(s); } + private static String assembleKey(Object key) { + String s = key.toString().toLowerCase(); + if (s.startsWith("camel")) { + // use intern String for headers which is Camel* headers + // this reduces memory allocations needed for those common headers + s = s.intern(); + } + return s; + } + @Override public synchronized Set<Map.Entry<String, Object>> entrySet() { if (entrySetView == null) { Modified: camel/trunk/camel-core/src/test/java/org/apache/camel/util/CaseInsensitiveMapTest.java URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/util/CaseInsensitiveMapTest.java?rev=1055489&r1=1055488&r2=1055489&view=diff ============================================================================== --- camel/trunk/camel-core/src/test/java/org/apache/camel/util/CaseInsensitiveMapTest.java (original) +++ camel/trunk/camel-core/src/test/java/org/apache/camel/util/CaseInsensitiveMapTest.java Wed Jan 5 15:32:33 2011 @@ -20,9 +20,11 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.CountDownLatch; @@ -476,4 +478,38 @@ public class CaseInsensitiveMapTest exte assertEquals("cheese", map.get("cAKe")); } + public void testCopyMapWithCamelHeadersTest() throws Exception { + Map<String, Object> map = new CaseInsensitiveMap(); + map.put("CamelA", "A"); + map.put("CamelB", "B"); + map.put("CamelC", "C"); + + // retain maps so we can profile that the map doesn't duplicate + // camel keys as they are intern + List<Map> maps = new ArrayList<Map>(); + + for (int i = 0; i < 10000; i++) { + Map<String, Object> copy = new CaseInsensitiveMap(map); + assertEquals(3, copy.size()); + assertEquals("A", copy.get("CamelA")); + assertEquals("B", copy.get("CamelB")); + assertEquals("C", copy.get("CamelC")); + + maps.add(copy); + } + + assertEquals(10000, maps.size()); + + assertEquals(3, map.size()); + assertEquals("A", map.get("CamelA")); + assertEquals("B", map.get("CamelB")); + assertEquals("C", map.get("CamelC")); + + // use a memory profiler to see memory allocation + // often you may want to give it time to run so you + // have chance to capture memory snapshot in profiler + // Thread.sleep(9999999); + } + + } \ No newline at end of file