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