You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2018/03/01 15:22:46 UTC
[1/2] groovy git commit: Make `UnlimitedConcurrentCache` implement
`EvictableCache`
Repository: groovy
Updated Branches:
refs/heads/master fd979347e -> 7ab1bd2bc
Make `UnlimitedConcurrentCache` implement `EvictableCache`
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/94bba384
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/94bba384
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/94bba384
Branch: refs/heads/master
Commit: 94bba38456f71c77c95284b8b9aa6d295cc695b4
Parents: fd97934
Author: danielsun1106 <re...@hotmail.com>
Authored: Thu Mar 1 23:20:54 2018 +0800
Committer: danielsun1106 <re...@hotmail.com>
Committed: Thu Mar 1 23:20:54 2018 +0800
----------------------------------------------------------------------
.../memoize/UnlimitedConcurrentCache.java | 149 +++++++++++++++-
...cheCleanupCollectedSoftReferencesTest.groovy | 12 +-
.../memoize/UnlimitedConcurrentCacheTest.java | 176 +++++++++++++++++++
3 files changed, 323 insertions(+), 14 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy/blob/94bba384/src/main/java/org/codehaus/groovy/runtime/memoize/UnlimitedConcurrentCache.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/memoize/UnlimitedConcurrentCache.java b/src/main/java/org/codehaus/groovy/runtime/memoize/UnlimitedConcurrentCache.java
index 874ab5d..0460fe9 100644
--- a/src/main/java/org/codehaus/groovy/runtime/memoize/UnlimitedConcurrentCache.java
+++ b/src/main/java/org/codehaus/groovy/runtime/memoize/UnlimitedConcurrentCache.java
@@ -18,8 +18,13 @@
*/
package org.codehaus.groovy.runtime.memoize;
+import javax.annotation.concurrent.ThreadSafe;
+import java.io.Serializable;
import java.lang.ref.SoftReference;
+import java.util.Collection;
+import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
@@ -27,27 +32,155 @@ import java.util.concurrent.ConcurrentHashMap;
*
* @author Vaclav Pech
*/
-public final class UnlimitedConcurrentCache implements MemoizeCache<Object, Object> {
+@ThreadSafe
+public final class UnlimitedConcurrentCache<K, V> implements EvictableCache<K, V>, Serializable {
+ private final ConcurrentHashMap<K, V> map;
- private final ConcurrentHashMap<Object, Object> cache = new ConcurrentHashMap<Object, Object>();
+ /**
+ * Constructs a cache with unlimited size
+ */
+ public UnlimitedConcurrentCache() {
+ map = new ConcurrentHashMap<K, V>();
+ }
+
+ /**
+ * Constructs a cache with unlimited size and set its initial capacity
+ * @param initialCapacity the initial capacity
+ */
+ public UnlimitedConcurrentCache(int initialCapacity) {
+ map = new ConcurrentHashMap<K, V>(initialCapacity);
+ }
- public Object put(final Object key, final Object value) {
- return cache.put(key, value);
+ /**
+ * Constructs a cache and initialize the cache with the specified map
+ * @param m the map to initialize the cache
+ */
+ public UnlimitedConcurrentCache(Map<? extends K, ? extends V> m) {
+ this();
+ map.putAll(m);
+ }
+
+ /**
+ * Remove the cached value by the key
+ *
+ * @param key
+ * @return returns the removed value
+ */
+ @Override
+ public V remove(K key) {
+ return map.remove(key);
}
- public Object get(final Object key) {
- return cache.get(key);
+ /**
+ * Clear the cache
+ *
+ * @return returns the content of the cleared map
+ */
+ @Override
+ public Map<K, V> clear() {
+ Map<K, V> result = new LinkedHashMap<K, V>(map.size());
+
+ for (Map.Entry<K, V> entry : map.entrySet()) {
+ K key = entry.getKey();
+ V value = entry.getValue();
+
+ boolean removed = map.remove(key, value);
+
+ if (removed) {
+ result.put(key, value);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Get all cached values
+ *
+ * @return all cached values
+ */
+ @Override
+ public Collection<V> values() {
+ return map.values();
+ }
+
+ /**
+ * Get all keys associated to cached values
+ *
+ * @return all keys
+ */
+ @Override
+ public Set<K> keys() {
+ return map.keySet();
+ }
+
+ /**
+ * Determines if the cache contains an entry for the specified key.
+ *
+ * @param key key whose presence in this cache is to be tested.
+ * @return true if the cache contains a mapping for the specified key
+ */
+ @Override
+ public boolean containsKey(K key) {
+ return map.containsKey(key);
+ }
+
+ /**
+ * Get the size of the cache
+ *
+ * @return the size of the cache
+ */
+ @Override
+ public int size() {
+ return map.size();
+ }
+
+ /**
+ * Associates the specified value with the specified key in the cache.
+ *
+ * @param key key with which the specified value is to be associated
+ * @param value value to be associated with the specified key
+ * @return null, or the old value if the key associated with the specified key.
+ */
+ @Override
+ public V put(K key, V value) {
+ return map.put(key, value);
+ }
+
+ /**
+ * Gets a value from the cache
+ *
+ * @param key the key whose associated value is to be returned
+ * @return the value, or null, if it does not exist.
+ */
+ @Override
+ public V get(K key) {
+ return map.get(key);
+ }
+
+ /**
+ * Try to get the value from cache.
+ * If not found, create the value by {@link ValueProvider} and put it into the cache, at last return the value.
+ *
+ * @param key
+ * @param valueProvider provide the value if the associated value not found
+ * @return the cached value
+ */
+ @Override
+ public V getAndPut(K key, ValueProvider<? super K, ? extends V> valueProvider) {
+ return map.computeIfAbsent(key, k -> valueProvider.provide(k));
}
/**
* Replying on the ConcurrentHashMap thread-safe iteration implementation the method will remove all entries holding
* SoftReferences to gc-evicted objects.
*/
+ @Override
public void cleanUpNullReferences() {
- for (Map.Entry<Object, Object> entry : cache.entrySet()) {
+ for (Map.Entry<K, V> entry : map.entrySet()) {
Object entryVal = entry.getValue();
if (entryVal instanceof SoftReference && ((SoftReference) entryVal).get() == null) {
- cache.remove(entry.getKey(), entryVal);
+ map.remove(entry.getKey(), entryVal);
}
}
}
http://git-wip-us.apache.org/repos/asf/groovy/blob/94bba384/src/test/org/codehaus/groovy/runtime/memoize/CacheCleanupCollectedSoftReferencesTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/org/codehaus/groovy/runtime/memoize/CacheCleanupCollectedSoftReferencesTest.groovy b/src/test/org/codehaus/groovy/runtime/memoize/CacheCleanupCollectedSoftReferencesTest.groovy
index 001104f..b48e87e 100644
--- a/src/test/org/codehaus/groovy/runtime/memoize/CacheCleanupCollectedSoftReferencesTest.groovy
+++ b/src/test/org/codehaus/groovy/runtime/memoize/CacheCleanupCollectedSoftReferencesTest.groovy
@@ -35,9 +35,9 @@ class CacheCleanupCollectedSoftReferencesTest extends GroovyTestCase {
UnlimitedConcurrentCache cache = new UnlimitedConcurrentCache()
Closure memoizedClosure = Memoize.buildSoftReferenceMemoizeFunction(0, cache, cl)
- assert cache.cache.size() == 0
+ assert cache.map.size() == 0
memoizedClosure.call(1)
- assert cache.cache.size() == 1
+ assert cache.map.size() == 1
forceSoftReferencesRecollection()
@@ -55,19 +55,19 @@ class CacheCleanupCollectedSoftReferencesTest extends GroovyTestCase {
UnlimitedConcurrentCache cache = new UnlimitedConcurrentCache()
Closure memoizedClosure = Memoize.buildSoftReferenceMemoizeFunction(0, cache, cl)
- assert cache.cache.size() == 0
+ assert cache.map.size() == 0
memoizedClosure.call(1)
- assert cache.cache.size() == 1
+ assert cache.map.size() == 1
forceSoftReferencesRecollection()
- assert cache.cache.size() == 1
+ assert cache.map.size() == 1
// As there is not a cleanup thread polling the ReferenceQueue,
// a call() invocation is needed to fire the cleaning up of null references.
memoizedClosure.call(2)
- assert cache.cache.size() == 1 : 'collected SoftReferences should be removed from cache'
+ assert cache.map.size() == 1 : 'collected SoftReferences should be removed from cache'
}
private void checkSoftReferenceAreSoftlyReachable(softReference) {
http://git-wip-us.apache.org/repos/asf/groovy/blob/94bba384/src/test/org/codehaus/groovy/runtime/memoize/UnlimitedConcurrentCacheTest.java
----------------------------------------------------------------------
diff --git a/src/test/org/codehaus/groovy/runtime/memoize/UnlimitedConcurrentCacheTest.java b/src/test/org/codehaus/groovy/runtime/memoize/UnlimitedConcurrentCacheTest.java
new file mode 100644
index 0000000..1e407e8
--- /dev/null
+++ b/src/test/org/codehaus/groovy/runtime/memoize/UnlimitedConcurrentCacheTest.java
@@ -0,0 +1,176 @@
+/*
+ * 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.lang.ref.SoftReference;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.TreeSet;
+
+public class UnlimitedConcurrentCacheTest {
+ @Test
+ public void get() {
+ UnlimitedConcurrentCache<String, String> sc =
+ new UnlimitedConcurrentCache<>(
+ 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() {
+ UnlimitedConcurrentCache<String, String> sc = new UnlimitedConcurrentCache<>();
+
+ 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() {
+ UnlimitedConcurrentCache<String, String> sc = new UnlimitedConcurrentCache<>();
+
+ EvictableCache.ValueProvider vp =
+ new EvictableCache.ValueProvider<String, String>() {
+ @Override
+ public String provide(String key) {
+ return "Chinese";
+ }
+ };
+
+ Assert.assertEquals("Chinese", sc.getAndPut("language", vp));
+ Assert.assertEquals("Chinese", sc.get("language"));
+ }
+
+ @Test
+ public void values() {
+ UnlimitedConcurrentCache<String, String> sc =
+ new UnlimitedConcurrentCache<>(
+ new LinkedHashMap<>(
+ Maps.of("name", "Daniel",
+ "gender", "Male",
+ "city", "Shanghai")
+ )
+ );
+
+ Assert.assertEquals(new TreeSet<>(Arrays.asList("Daniel", "Male", "Shanghai")), new TreeSet<>(sc.values()));
+ }
+
+ @Test
+ public void keys() {
+ UnlimitedConcurrentCache<String, String> sc =
+ new UnlimitedConcurrentCache<>(
+ new LinkedHashMap<>(
+ Maps.of("name", "Daniel",
+ "gender", "Male",
+ "city", "Shanghai")
+ )
+ );
+
+ Assert.assertEquals(new TreeSet<>(Arrays.asList("name", "gender", "city")), new TreeSet<>(sc.keys()));
+ }
+
+ @Test
+ public void containsKey() {
+ UnlimitedConcurrentCache<String, String> sc =
+ new UnlimitedConcurrentCache<>(
+ new LinkedHashMap<>(
+ Maps.of("name", "Daniel",
+ "gender", "Male",
+ "city", "Shanghai")
+ )
+ );
+
+ Assert.assertTrue(sc.containsKey("name"));
+ }
+
+ @Test
+ public void size() {
+ UnlimitedConcurrentCache<String, String> sc =
+ new UnlimitedConcurrentCache<>(
+ new LinkedHashMap<>(
+ Maps.of("name", "Daniel",
+ "gender", "Male",
+ "city", "Shanghai")
+ )
+ );
+
+ Assert.assertEquals(3, sc.size());
+ }
+
+ @Test
+ public void remove() {
+ UnlimitedConcurrentCache<String, String> sc =
+ new UnlimitedConcurrentCache<>(
+ 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() {
+ UnlimitedConcurrentCache<String, String> sc =
+ new UnlimitedConcurrentCache<>(
+ new LinkedHashMap<>(
+ Maps.of("name", "Daniel",
+ "gender", "Male",
+ "city", "Shanghai")
+ )
+ );
+
+ Assert.assertEquals(new TreeSet<>(Arrays.asList("Daniel", "Male", "Shanghai")), new TreeSet<>(sc.clear().values()));
+ }
+
+ @Test
+ public void cleanUpNullReferences() {
+ UnlimitedConcurrentCache<String, Object> sc =
+ new UnlimitedConcurrentCache<>(
+ new LinkedHashMap<>(
+ Maps.of("name", "Daniel",
+ "gender", "Male",
+ "city", new SoftReference(null))
+ )
+ );
+
+ sc.cleanUpNullReferences();
+ Assert.assertEquals(new TreeSet<>(Arrays.asList("Daniel", "Male")), new TreeSet<>(sc.values()));
+ }
+
+}
[2/2] groovy git commit: Use `UnlimitedConcurrentCache` to cache
classes
Posted by su...@apache.org.
Use `UnlimitedConcurrentCache` to cache classes
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/7ab1bd2b
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/7ab1bd2b
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/7ab1bd2b
Branch: refs/heads/master
Commit: 7ab1bd2bcf8301a76c85d61b1f95402561e68373
Parents: 94bba38
Author: danielsun1106 <re...@hotmail.com>
Authored: Thu Mar 1 23:21:30 2018 +0800
Committer: danielsun1106 <re...@hotmail.com>
Committed: Thu Mar 1 23:21:30 2018 +0800
----------------------------------------------------------------------
src/main/groovy/groovy/lang/GroovyClassLoader.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy/blob/7ab1bd2b/src/main/groovy/groovy/lang/GroovyClassLoader.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/GroovyClassLoader.java b/src/main/groovy/groovy/lang/GroovyClassLoader.java
index 8581879..07d946f 100644
--- a/src/main/groovy/groovy/lang/GroovyClassLoader.java
+++ b/src/main/groovy/groovy/lang/GroovyClassLoader.java
@@ -45,6 +45,7 @@ import org.codehaus.groovy.runtime.IOGroovyMethods;
import org.codehaus.groovy.runtime.InvokerHelper;
import org.codehaus.groovy.runtime.memoize.ConcurrentCommonCache;
import org.codehaus.groovy.runtime.memoize.EvictableCache;
+import org.codehaus.groovy.runtime.memoize.UnlimitedConcurrentCache;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
@@ -96,7 +97,7 @@ public class GroovyClassLoader extends URLClassLoader {
/**
* this cache contains the loaded classes or PARSING, if the class is currently parsed
*/
- protected final EvictableCache<String, Class> classCache = new ConcurrentCommonCache<String, Class>();
+ protected final EvictableCache<String, Class> classCache = new UnlimitedConcurrentCache<String, Class>();
/**
* This cache contains mappings of file name to class. It is used