Repository: groovy Updated Branches: refs/heads/GROOVY_2_6_X d2526ca6b -> 97ea41739
Minor refactoring: Split the implementation of CommonCache into thread-safe and not thread-safe (cherry picked from commit 29727ea) Project: http://git-wip-us.apache.org/repos/asf/groovy/repo Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/fbd28869 Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/fbd28869 Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/fbd28869 Branch: refs/heads/GROOVY_2_6_X Commit: fbd288690ed11cdfe7d7a4a047e9fbb2fd447648 Parents: d2526ca Author: sunlan <sun...@apache.org> Authored: Mon Dec 11 23:06:53 2017 +0800 Committer: sunlan <sun...@apache.org> Committed: Mon Dec 11 23:51:40 2017 +0800 ---------------------------------------------------------------------- src/main/groovy/lang/GroovyClassLoader.java | 6 +- .../groovy/runtime/memoize/CommonCache.java | 136 +++-------- .../runtime/memoize/ConcurrentCommonCache.java | 240 +++++++++++++++++++ .../stc/StaticTypeCheckingSupport.java | 4 +- .../groovy/runtime/memoize/CommonCacheTest.java | 175 -------------- .../memoize/ConcurrentCommonCacheTest.java | 175 ++++++++++++++ .../macro/transform/MacroMethodsCache.java | 4 +- 7 files changed, 452 insertions(+), 288 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/groovy/blob/fbd28869/src/main/groovy/lang/GroovyClassLoader.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/lang/GroovyClassLoader.java b/src/main/groovy/lang/GroovyClassLoader.java index 47e5444..a491fc0 100644 --- a/src/main/groovy/lang/GroovyClassLoader.java +++ b/src/main/groovy/lang/GroovyClassLoader.java @@ -44,7 +44,7 @@ import org.codehaus.groovy.control.SourceUnit; import org.codehaus.groovy.runtime.IOGroovyMethods; import org.codehaus.groovy.runtime.InvokerHelper; import org.codehaus.groovy.runtime.memoize.EvictableCache; -import org.codehaus.groovy.runtime.memoize.CommonCache; +import org.codehaus.groovy.runtime.memoize.ConcurrentCommonCache; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Opcodes; @@ -95,13 +95,13 @@ public class GroovyClassLoader extends URLClassLoader { /** * this cache contains the loaded classes or PARSING, if the class is currently parsed */ - protected final CommonCache<String, Class> classCache = new CommonCache<String, Class>(); + protected final ConcurrentCommonCache<String, Class> classCache = new ConcurrentCommonCache<String, Class>(); /** * This cache contains mappings of file name to class. It is used * to bypass compilation. */ - protected final CommonCache<String, Class> sourceCache = new CommonCache<String, Class>(); + protected final ConcurrentCommonCache<String, Class> sourceCache = new ConcurrentCommonCache<String, Class>(); private final CompilerConfiguration config; private String sourceEncoding; http://git-wip-us.apache.org/repos/asf/groovy/blob/fbd28869/src/main/org/codehaus/groovy/runtime/memoize/CommonCache.java ---------------------------------------------------------------------- diff --git a/src/main/org/codehaus/groovy/runtime/memoize/CommonCache.java b/src/main/org/codehaus/groovy/runtime/memoize/CommonCache.java index 1bd336d..dd29d5b 100644 --- a/src/main/org/codehaus/groovy/runtime/memoize/CommonCache.java +++ b/src/main/org/codehaus/groovy/runtime/memoize/CommonCache.java @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ + package org.codehaus.groovy.runtime.memoize; import java.lang.ref.SoftReference; @@ -26,11 +27,10 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.locks.ReentrantReadWriteLock; /** * - * Represents a simple key-value cache, which is thread safe and backed by a {@link java.util.Map} instance + * Represents a simple key-value cache, which is NOT thread safe and backed by a {@link java.util.Map} instance * * @param <K> type of the keys * @param <V> type of the values @@ -39,9 +39,6 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; */ public class CommonCache<K, V> implements EvictableCache<K, V> { private final Map<K, V> map; - private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); - private final ReentrantReadWriteLock.ReadLock readLock = rwl.readLock(); - private final ReentrantReadWriteLock.WriteLock writeLock = rwl.writeLock(); /** * Constructs a cache with unlimited size @@ -97,16 +94,7 @@ public class CommonCache<K, V> implements EvictableCache<K, V> { */ @Override public V get(K key) { - if (null == key) { - return null; - } - - readLock.lock(); - try { - return map.get(key); - } finally { - readLock.unlock(); - } + return map.get(key); } /** @@ -114,13 +102,7 @@ public class CommonCache<K, V> implements EvictableCache<K, V> { */ @Override public V put(K key, V value) { - writeLock.lock(); - try { - return map.put(key, value); - } finally { - writeLock.unlock(); - } - + return map.put(key, value); } /** @@ -132,36 +114,14 @@ public class CommonCache<K, V> implements EvictableCache<K, V> { } public V getAndPut(K key, ValueProvider<K, V> valueProvider, boolean shouldCache) { - if (null == key) { - return null; + V value = map.get(key); + if (null != value) { + return value; } - V value; - - readLock.lock(); - try { - value = map.get(key); - if (null != value) { - return value; - } - } finally { - readLock.unlock(); - } - - writeLock.lock(); - try { - // try to find the cached value again - value = map.get(key); - if (null != value) { - return value; - } - - value = null == valueProvider ? null : valueProvider.provide(key); - if (shouldCache && null != value) { - map.put(key, value); - } - } finally { - writeLock.unlock(); + value = null == valueProvider ? null : valueProvider.provide(key); + if (shouldCache && null != value) { + map.put(key, value); } return value; @@ -172,12 +132,7 @@ public class CommonCache<K, V> implements EvictableCache<K, V> { */ @Override public Collection<V> values() { - readLock.lock(); - try { - return map.values(); - } finally { - readLock.unlock(); - } + return map.values(); } /** @@ -185,12 +140,7 @@ public class CommonCache<K, V> implements EvictableCache<K, V> { */ @Override public Set<K> keys() { - readLock.lock(); - try { - return map.keySet(); - } finally { - readLock.unlock(); - } + return map.keySet(); } /** @@ -198,12 +148,7 @@ public class CommonCache<K, V> implements EvictableCache<K, V> { */ @Override public boolean containsKey(K key) { - readLock.lock(); - try { - return map.containsKey(key); - } finally { - readLock.unlock(); - } + return map.containsKey(key); } /** @@ -211,12 +156,7 @@ public class CommonCache<K, V> implements EvictableCache<K, V> { */ @Override public int size() { - readLock.lock(); - try { - return map.size(); - } finally { - readLock.unlock(); - } + return map.size(); } /** @@ -224,12 +164,7 @@ public class CommonCache<K, V> implements EvictableCache<K, V> { */ @Override public V remove(K key) { - writeLock.lock(); - try { - return map.remove(key); - } finally { - writeLock.unlock(); - } + return map.remove(key); } /** @@ -237,15 +172,8 @@ public class CommonCache<K, V> implements EvictableCache<K, V> { */ @Override public Collection<V> clear() { - Collection<V> values; - - writeLock.lock(); - try { - values = map.values(); - map.clear(); - } finally { - writeLock.unlock(); - } + Collection<V> values = map.values(); + map.clear(); return values; } @@ -255,25 +183,21 @@ public class CommonCache<K, V> implements EvictableCache<K, V> { */ @Override public void cleanUpNullReferences() { - writeLock.lock(); - try { - List<K> keys = new LinkedList<>(); - - for (Map.Entry<K, V> entry : map.entrySet()) { - K key = entry.getKey(); - V value = entry.getValue(); - if (null == value - || (value instanceof SoftReference && null == ((SoftReference) value).get()) - || (value instanceof WeakReference && null == ((WeakReference) value).get())) { - keys.add(key); - } + List<K> keys = new LinkedList<>(); + + for (Map.Entry<K, V> entry : map.entrySet()) { + K key = entry.getKey(); + V value = entry.getValue(); + if (null == value + || (value instanceof SoftReference && null == ((SoftReference) value).get()) + || (value instanceof WeakReference && null == ((WeakReference) value).get())) { + keys.add(key); } + } - for (K key : keys) { - map.remove(key); - } - } finally { - writeLock.unlock(); + for (K key : keys) { + map.remove(key); } } + } http://git-wip-us.apache.org/repos/asf/groovy/blob/fbd28869/src/main/org/codehaus/groovy/runtime/memoize/ConcurrentCommonCache.java ---------------------------------------------------------------------- diff --git a/src/main/org/codehaus/groovy/runtime/memoize/ConcurrentCommonCache.java b/src/main/org/codehaus/groovy/runtime/memoize/ConcurrentCommonCache.java new file mode 100644 index 0000000..81345d9 --- /dev/null +++ b/src/main/org/codehaus/groovy/runtime/memoize/ConcurrentCommonCache.java @@ -0,0 +1,240 @@ +/* + * 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.codehaus.groovy.runtime.memoize; + +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * + * Represents a simple key-value cache, which is thread safe and backed by a {@link java.util.Map} instance + * + * @param <K> type of the keys + * @param <V> type of the values + * + * @since 2.5.0 + */ +public class ConcurrentCommonCache<K, V> extends CommonCache<K, V> { + private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); + private final ReentrantReadWriteLock.ReadLock readLock = rwl.readLock(); + private final ReentrantReadWriteLock.WriteLock writeLock = rwl.writeLock(); + + /** + * Constructs a cache with unlimited size + */ + public ConcurrentCommonCache() {} + + /** + * Constructs a cache with limited size + * @param initialCapacity initial capacity of the LRU cache + * @param maxSize max size of the LRU cache + * @param accessOrder the ordering mode - <tt>true</tt> for access-order, <tt>false</tt> for insertion-order, see the parameter accessOrder of {@link LinkedHashMap#LinkedHashMap(int, float, boolean)} + */ + public ConcurrentCommonCache(int initialCapacity, int maxSize, boolean accessOrder) { + super(initialCapacity, maxSize, accessOrder); + } + + /** + * Constructs a LRU cache with the specified initial capacity and max size. + * The LRU cache is slower than {@link LRUCache} but will not put same value multi-times concurrently + * @param initialCapacity initial capacity of the LRU cache + * @param maxSize max size of the LRU cache + */ + public ConcurrentCommonCache(int initialCapacity, int maxSize) { + super(initialCapacity, maxSize); + } + + /** + * Constructs a LRU cache with the default initial capacity(16) + * @param maxSize max size of the LRU cache + * @see #ConcurrentCommonCache(int, int) + */ + public ConcurrentCommonCache(int maxSize) { + super(maxSize); + } + + /** + * Constructs a cache backed by the specified {@link java.util.Map} instance + * @param map the {@link java.util.Map} instance + */ + public ConcurrentCommonCache(Map<K, V> map) { + super(map); + } + + /** + * {@inheritDoc} + */ + @Override + public V get(K key) { + readLock.lock(); + try { + return super.get(key); + } finally { + readLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public V put(K key, V value) { + writeLock.lock(); + try { + return super.put(key, value); + } finally { + writeLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public V getAndPut(K key, ValueProvider<K, V> valueProvider) { + return getAndPut(key, valueProvider, true); + } + + @Override + public V getAndPut(K key, ValueProvider<K, V> valueProvider, boolean shouldCache) { + V value; + + readLock.lock(); + try { + value = super.get(key); + if (null != value) { + return value; + } + } finally { + readLock.unlock(); + } + + writeLock.lock(); + try { + // try to find the cached value again + value = super.get(key); + if (null != value) { + return value; + } + + value = null == valueProvider ? null : valueProvider.provide(key); + if (shouldCache && null != value) { + super.put(key, value); + } + } finally { + writeLock.unlock(); + } + + return value; + } + + /** + * {@inheritDoc} + */ + @Override + public Collection<V> values() { + readLock.lock(); + try { + return super.values(); + } finally { + readLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public Set<K> keys() { + readLock.lock(); + try { + return super.keys(); + } finally { + readLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean containsKey(K key) { + readLock.lock(); + try { + return super.containsKey(key); + } finally { + readLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public int size() { + readLock.lock(); + try { + return super.size(); + } finally { + readLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public V remove(K key) { + writeLock.lock(); + try { + return super.remove(key); + } finally { + writeLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public Collection<V> clear() { + writeLock.lock(); + try { + return super.clear(); + } finally { + writeLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void cleanUpNullReferences() { + writeLock.lock(); + try { + super.cleanUpNullReferences(); + } finally { + writeLock.unlock(); + } + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/fbd28869/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java ---------------------------------------------------------------------- diff --git a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java index b326061..301671b 100644 --- a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java +++ b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java @@ -46,7 +46,7 @@ import org.codehaus.groovy.runtime.DefaultGroovyStaticMethods; import org.codehaus.groovy.runtime.m12n.ExtensionModule; import org.codehaus.groovy.runtime.m12n.ExtensionModuleScanner; import org.codehaus.groovy.runtime.m12n.MetaInfExtensionModule; -import org.codehaus.groovy.runtime.memoize.CommonCache; +import org.codehaus.groovy.runtime.memoize.ConcurrentCommonCache; import org.codehaus.groovy.runtime.memoize.EvictableCache; import org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl; import org.codehaus.groovy.tools.GroovyClass; @@ -2162,7 +2162,7 @@ public abstract class StaticTypeCheckingSupport { * a method lookup. */ private static class ExtensionMethodCache { - private final CommonCache<ClassLoader, Map<String, List<MethodNode>>> cache = new CommonCache<ClassLoader, Map<String, List<MethodNode>>>(new WeakHashMap<ClassLoader, Map<String, List<MethodNode>>>()); + private final ConcurrentCommonCache<ClassLoader, Map<String, List<MethodNode>>> cache = new ConcurrentCommonCache<ClassLoader, Map<String, List<MethodNode>>>(new WeakHashMap<ClassLoader, Map<String, List<MethodNode>>>()); public Map<String, List<MethodNode>> getExtensionMethods(ClassLoader loader) { return cache.getAndPut( http://git-wip-us.apache.org/repos/asf/groovy/blob/fbd28869/src/test/org/codehaus/groovy/runtime/memoize/CommonCacheTest.java ---------------------------------------------------------------------- diff --git a/src/test/org/codehaus/groovy/runtime/memoize/CommonCacheTest.java b/src/test/org/codehaus/groovy/runtime/memoize/CommonCacheTest.java deleted file mode 100644 index 9fb4350..0000000 --- a/src/test/org/codehaus/groovy/runtime/memoize/CommonCacheTest.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * 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.codehaus.groovy.runtime.memoize; - -import org.apache.groovy.util.Maps; -import org.junit.Assert; -import org.junit.Test; - -import java.util.HashMap; -import java.util.LinkedHashMap; - -public class CommonCacheTest { - @Test - public void get() { - CommonCache<String, String> sc = - new CommonCache<>( - new LinkedHashMap<>( - Maps.of("name", "Daniel", - "gender", "Male", - "city", "Shanghai") - ) - ); - - Assert.assertEquals("Daniel", sc.get("name")); - Assert.assertEquals("Male", sc.get("gender")); - Assert.assertEquals("Shanghai", sc.get("city")); - Assert.assertNull(sc.get("foo")); - } - - @Test - public void put() { - CommonCache<String, String> sc = new CommonCache<>(); - - Assert.assertNull(sc.put("name", "Daniel")); - Assert.assertEquals("Daniel", sc.get("name")); - - Assert.assertEquals("Daniel", sc.put("name", "sunlan")); - Assert.assertEquals("sunlan", sc.get("name")); - } - - @Test - public void getAndPut() { - CommonCache<String, String> sc = new CommonCache<>(); - - EvictableCache.ValueProvider vp = - new EvictableCache.ValueProvider<String, String>() { - @Override - public String provide(String key) { - return "Chinese"; - } - }; - - Assert.assertEquals("Chinese", sc.getAndPut("language", vp,false)); - Assert.assertNull(sc.get("language")); - - Assert.assertEquals("Chinese", sc.getAndPut("language", vp)); - Assert.assertEquals("Chinese", sc.get("language")); - } - - @Test - public void values() { - CommonCache<String, String> sc = - new CommonCache<>( - new LinkedHashMap<>( - Maps.of("name", "Daniel", - "gender", "Male", - "city", "Shanghai") - ) - ); - - Assert.assertArrayEquals(new String[] {"Daniel", "Male", "Shanghai"}, sc.values().toArray(new String[0])); - } - - @Test - public void keys() { - CommonCache<String, String> sc = - new CommonCache<>( - new LinkedHashMap<>( - Maps.of("name", "Daniel", - "gender", "Male", - "city", "Shanghai") - ) - ); - - Assert.assertArrayEquals(new String[] {"name", "gender", "city"}, sc.keys().toArray(new String[0])); - } - - @Test - public void containsKey() { - CommonCache<String, String> sc = - new CommonCache<>( - new LinkedHashMap<>( - Maps.of("name", "Daniel", - "gender", "Male", - "city", "Shanghai") - ) - ); - - Assert.assertTrue(sc.containsKey("name")); - } - - @Test - public void size() { - CommonCache<String, String> sc = - new CommonCache<>( - new LinkedHashMap<>( - Maps.of("name", "Daniel", - "gender", "Male", - "city", "Shanghai") - ) - ); - - Assert.assertEquals(3, sc.size()); - } - - @Test - public void remove() { - CommonCache<String, String> sc = - new CommonCache<>( - new HashMap<>( - Maps.of("name", "Daniel", - "gender", "Male", - "city", "Shanghai") - ) - ); - - Assert.assertEquals("Shanghai", sc.remove("city")); - Assert.assertNull(sc.get("city")); - } - - @Test - public void clear() { - CommonCache<String, String> sc = - new CommonCache<>( - new LinkedHashMap<>( - Maps.of("name", "Daniel", - "gender", "Male", - "city", "Shanghai") - ) - ); - - Assert.assertArrayEquals(new String[] {"Daniel", "Male", "Shanghai"}, sc.values().toArray(new String[0])); - } - - @Test - public void cleanUpNullReferences() { - CommonCache<String, String> sc = - new CommonCache<>( - new LinkedHashMap<>( - Maps.of("name", "Daniel", - "gender", "Male", - "city", null) - ) - ); - - sc.cleanUpNullReferences(); - Assert.assertArrayEquals(new String[] {"Daniel", "Male"}, sc.values().toArray(new String[0])); - } -} http://git-wip-us.apache.org/repos/asf/groovy/blob/fbd28869/src/test/org/codehaus/groovy/runtime/memoize/ConcurrentCommonCacheTest.java ---------------------------------------------------------------------- diff --git a/src/test/org/codehaus/groovy/runtime/memoize/ConcurrentCommonCacheTest.java b/src/test/org/codehaus/groovy/runtime/memoize/ConcurrentCommonCacheTest.java new file mode 100644 index 0000000..e78c6e2 --- /dev/null +++ b/src/test/org/codehaus/groovy/runtime/memoize/ConcurrentCommonCacheTest.java @@ -0,0 +1,175 @@ +/* + * 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.codehaus.groovy.runtime.memoize; + +import org.apache.groovy.util.Maps; +import org.junit.Assert; +import org.junit.Test; + +import java.util.HashMap; +import java.util.LinkedHashMap; + +public class ConcurrentCommonCacheTest { + @Test + public void get() { + ConcurrentCommonCache<String, String> sc = + new ConcurrentCommonCache<>( + new LinkedHashMap<>( + Maps.of("name", "Daniel", + "gender", "Male", + "city", "Shanghai") + ) + ); + + Assert.assertEquals("Daniel", sc.get("name")); + Assert.assertEquals("Male", sc.get("gender")); + Assert.assertEquals("Shanghai", sc.get("city")); + Assert.assertNull(sc.get("foo")); + } + + @Test + public void put() { + ConcurrentCommonCache<String, String> sc = new ConcurrentCommonCache<>(); + + Assert.assertNull(sc.put("name", "Daniel")); + Assert.assertEquals("Daniel", sc.get("name")); + + Assert.assertEquals("Daniel", sc.put("name", "sunlan")); + Assert.assertEquals("sunlan", sc.get("name")); + } + + @Test + public void getAndPut() { + ConcurrentCommonCache<String, String> sc = new ConcurrentCommonCache<>(); + + EvictableCache.ValueProvider vp = + new EvictableCache.ValueProvider<String, String>() { + @Override + public String provide(String key) { + return "Chinese"; + } + }; + + Assert.assertEquals("Chinese", sc.getAndPut("language", vp,false)); + Assert.assertNull(sc.get("language")); + + Assert.assertEquals("Chinese", sc.getAndPut("language", vp)); + Assert.assertEquals("Chinese", sc.get("language")); + } + + @Test + public void values() { + ConcurrentCommonCache<String, String> sc = + new ConcurrentCommonCache<>( + new LinkedHashMap<>( + Maps.of("name", "Daniel", + "gender", "Male", + "city", "Shanghai") + ) + ); + + Assert.assertArrayEquals(new String[] {"Daniel", "Male", "Shanghai"}, sc.values().toArray(new String[0])); + } + + @Test + public void keys() { + ConcurrentCommonCache<String, String> sc = + new ConcurrentCommonCache<>( + new LinkedHashMap<>( + Maps.of("name", "Daniel", + "gender", "Male", + "city", "Shanghai") + ) + ); + + Assert.assertArrayEquals(new String[] {"name", "gender", "city"}, sc.keys().toArray(new String[0])); + } + + @Test + public void containsKey() { + ConcurrentCommonCache<String, String> sc = + new ConcurrentCommonCache<>( + new LinkedHashMap<>( + Maps.of("name", "Daniel", + "gender", "Male", + "city", "Shanghai") + ) + ); + + Assert.assertTrue(sc.containsKey("name")); + } + + @Test + public void size() { + ConcurrentCommonCache<String, String> sc = + new ConcurrentCommonCache<>( + new LinkedHashMap<>( + Maps.of("name", "Daniel", + "gender", "Male", + "city", "Shanghai") + ) + ); + + Assert.assertEquals(3, sc.size()); + } + + @Test + public void remove() { + ConcurrentCommonCache<String, String> sc = + new ConcurrentCommonCache<>( + new HashMap<>( + Maps.of("name", "Daniel", + "gender", "Male", + "city", "Shanghai") + ) + ); + + Assert.assertEquals("Shanghai", sc.remove("city")); + Assert.assertNull(sc.get("city")); + } + + @Test + public void clear() { + ConcurrentCommonCache<String, String> sc = + new ConcurrentCommonCache<>( + new LinkedHashMap<>( + Maps.of("name", "Daniel", + "gender", "Male", + "city", "Shanghai") + ) + ); + + Assert.assertArrayEquals(new String[] {"Daniel", "Male", "Shanghai"}, sc.values().toArray(new String[0])); + } + + @Test + public void cleanUpNullReferences() { + ConcurrentCommonCache<String, String> sc = + new ConcurrentCommonCache<>( + new LinkedHashMap<>( + Maps.of("name", "Daniel", + "gender", "Male", + "city", null) + ) + ); + + sc.cleanUpNullReferences(); + Assert.assertArrayEquals(new String[] {"Daniel", "Male"}, sc.values().toArray(new String[0])); + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/fbd28869/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroMethodsCache.java ---------------------------------------------------------------------- diff --git a/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroMethodsCache.java b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroMethodsCache.java index 01201fd..13cf2b2 100644 --- a/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroMethodsCache.java +++ b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroMethodsCache.java @@ -26,7 +26,7 @@ import org.codehaus.groovy.macro.runtime.Macro; import org.codehaus.groovy.runtime.m12n.ExtensionModule; import org.codehaus.groovy.runtime.m12n.ExtensionModuleScanner; import org.codehaus.groovy.runtime.m12n.MetaInfExtensionModule; -import org.codehaus.groovy.runtime.memoize.CommonCache; +import org.codehaus.groovy.runtime.memoize.ConcurrentCommonCache; import org.codehaus.groovy.runtime.memoize.EvictableCache; import org.codehaus.groovy.transform.stc.ExtensionMethodNode; @@ -44,7 +44,7 @@ import java.util.WeakHashMap; */ class MacroMethodsCache { private static final ClassNode MACRO_ANNOTATION_CLASS_NODE = ClassHelper.make(Macro.class); - private static final CommonCache<ClassLoader, Map<String, List<MethodNode>>> CACHE = new CommonCache<ClassLoader, Map<String, List<MethodNode>>>(new WeakHashMap<ClassLoader, Map<String, List<MethodNode>>>()); + private static final ConcurrentCommonCache<ClassLoader, Map<String, List<MethodNode>>> CACHE = new ConcurrentCommonCache<ClassLoader, Map<String, List<MethodNode>>>(new WeakHashMap<ClassLoader, Map<String, List<MethodNode>>>()); public static Map<String, List<MethodNode>> get(final ClassLoader classLoader) { return CACHE.getAndPut(classLoader, new EvictableCache.ValueProvider<ClassLoader, Map<String, List<MethodNode>>>() {