You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by rm...@apache.org on 2018/05/22 15:05:24 UTC

[geronimo-jcache-simple] branch master updated: ensure onEvicted is called on listeners

This is an automated email from the ASF dual-hosted git repository.

rmannibucau pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/geronimo-jcache-simple.git


The following commit(s) were added to refs/heads/master by this push:
     new a931ebc  ensure onEvicted is called on listeners
a931ebc is described below

commit a931ebce10b043a3eb8f8b31895304dea79e05e8
Author: Romain Manni-Bucau <rm...@gmail.com>
AuthorDate: Tue May 22 17:05:22 2018 +0200

    ensure onEvicted is called on listeners
---
 .../apache/geronimo/jcache/simple/SimpleCache.java | 30 ++++----
 .../jcache/simple/tck/ExpiryListenerTest.java      | 85 ++++++++++++++++++++++
 2 files changed, 102 insertions(+), 13 deletions(-)

diff --git a/src/main/java/org/apache/geronimo/jcache/simple/SimpleCache.java b/src/main/java/org/apache/geronimo/jcache/simple/SimpleCache.java
index b6d95bc..43e49b3 100644
--- a/src/main/java/org/apache/geronimo/jcache/simple/SimpleCache.java
+++ b/src/main/java/org/apache/geronimo/jcache/simple/SimpleCache.java
@@ -30,7 +30,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
-import java.util.TreeSet;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ExecutorService;
@@ -112,7 +111,7 @@ public class SimpleCache<K, V> implements Cache<K, V> {
                 properties.getProperty(cacheName + ".evictionPause", properties.getProperty("evictionPause", "30000")));
         if (evictionPause > 0) {
             final long maxDeleteByEvictionRun = Long.parseLong(property(properties, cacheName, "maxDeleteByEvictionRun", "100"));
-            pool.submit(new EvictionThread<>(this, evictionPause, maxDeleteByEvictionRun));
+            pool.submit(new EvictionThread(evictionPause, maxDeleteByEvictionRun));
         }
 
         serializations = new Serializations(property(properties, cacheName, "serialization.whitelist", null));
@@ -286,6 +285,10 @@ public class SimpleCache<K, V> implements Cache<K, V> {
     private void expires(final SimpleKey<K> cacheKey) {
         final SimpleElement<V> elt = delegate.get(cacheKey);
         delegate.remove(cacheKey);
+        onExpired(cacheKey, elt);
+    }
+
+    private void onExpired(final SimpleKey<K> cacheKey, final SimpleElement<V> elt) {
         for (final SimpleListener<K, V> listener : listeners.values()) {
             listener.onExpired(Collections.<CacheEntryEvent<? extends K, ? extends V>> singletonList(
                     new SimpleEvent<>(this, EventType.REMOVED, null, cacheKey.getKey(), elt.getElement())));
@@ -778,32 +781,32 @@ public class SimpleCache<K, V> implements Cache<K, V> {
         }
     }
 
-    private static class EvictionThread<K> implements Runnable {
+    private class EvictionThread implements Runnable {
 
         private final long pause;
 
         private final long maxDelete;
 
-        private final SimpleCache<K, ?> cache;
-
-        private EvictionThread(final SimpleCache<K, ?> cache, final long evictionPause, final long maxDelete) {
-            this.cache = cache;
+        private EvictionThread(final long evictionPause, final long maxDelete) {
             this.pause = evictionPause;
             this.maxDelete = maxDelete;
         }
 
         @Override
         public void run() {
-            while (!cache.isClosed()) {
+            while (!isClosed()) {
                 try {
-                    Thread.sleep(pause * 10000);
+                    Thread.sleep(pause);
                 } catch (final InterruptedException e) {
                     Thread.currentThread().interrupt();
                     break;
                 }
+                if (delegate.isEmpty()) {
+                    continue;
+                }
 
                 try {
-                    final List<SimpleKey<K>> keys = new ArrayList<>(new TreeSet<>(cache.delegate.keySet()));
+                    final List<SimpleKey<K>> keys = new ArrayList<>(delegate.keySet());
                     Collections.sort(keys, new Comparator<SimpleKey<K>>() {
 
                         @Override
@@ -818,10 +821,11 @@ public class SimpleCache<K, V> implements Cache<K, V> {
 
                     int delete = 0;
                     for (final SimpleKey<K> key : keys) {
-                        final SimpleElement<?> elt = cache.delegate.get(key);
+                        final SimpleElement<V> elt = delegate.get(key);
                         if (elt != null && elt.isExpired()) {
-                            cache.delegate.remove(key);
-                            cache.statistics.increaseEvictions(1);
+                            delegate.remove(key);
+                            statistics.increaseEvictions(1);
+                            onExpired(key, elt);
                             delete++;
                             if (delete >= maxDelete) {
                                 break;
diff --git a/src/test/java/org/apache/geronimo/jcache/simple/tck/ExpiryListenerTest.java b/src/test/java/org/apache/geronimo/jcache/simple/tck/ExpiryListenerTest.java
new file mode 100644
index 0000000..2045437
--- /dev/null
+++ b/src/test/java/org/apache/geronimo/jcache/simple/tck/ExpiryListenerTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.geronimo.jcache.simple.tck;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Properties;
+import java.util.concurrent.TimeUnit;
+
+import javax.cache.Cache;
+import javax.cache.CacheManager;
+import javax.cache.Caching;
+import javax.cache.configuration.FactoryBuilder;
+import javax.cache.configuration.MutableCacheEntryListenerConfiguration;
+import javax.cache.configuration.MutableConfiguration;
+import javax.cache.event.CacheEntryEvent;
+import javax.cache.event.CacheEntryExpiredListener;
+import javax.cache.event.CacheEntryListenerException;
+import javax.cache.expiry.CreatedExpiryPolicy;
+import javax.cache.expiry.Duration;
+import javax.cache.expiry.ExpiryPolicy;
+import javax.cache.spi.CachingProvider;
+
+import org.junit.Test;
+
+public class ExpiryListenerTest {
+
+    @Test
+    public void listener() throws InterruptedException {
+        final CachingProvider cachingProvider = Caching.getCachingProvider();
+        final CacheManager cacheManager = cachingProvider.getCacheManager(cachingProvider.getDefaultURI(),
+                cachingProvider.getDefaultClassLoader(),
+                new Properties() {{
+                    setProperty("evictionPause", "2");
+                }});
+        final CacheEntryExpiredListenerImpl listener = new CacheEntryExpiredListenerImpl();
+        cacheManager.createCache("default", new MutableConfiguration<String, String>()
+                .setExpiryPolicyFactory(new FactoryBuilder.SingletonFactory<ExpiryPolicy>(
+                        new CreatedExpiryPolicy(new Duration(TimeUnit.MILLISECONDS, 2))))
+                .addCacheEntryListenerConfiguration(new MutableCacheEntryListenerConfiguration<String, String>(
+                        FactoryBuilder.factoryOf(listener),
+                        null, false, false
+                )));
+        final Cache<String, String> cache = cacheManager.getCache("default");
+        assertFalse(cache.containsKey("foo"));
+        cache.put("foo", "bar");
+        Thread.sleep(20);
+        assertEquals(1, listener.events.size());
+        cachingProvider.close();
+    }
+
+    private static class CacheEntryExpiredListenerImpl implements CacheEntryExpiredListener<String, String>, Serializable {
+        private final Collection<CacheEntryEvent<? extends String, ? extends String>> events =
+                new ArrayList<CacheEntryEvent<? extends String, ? extends String>>();
+
+        @Override
+        public void onExpired(final Iterable<CacheEntryEvent<? extends String, ? extends String>> cacheEntryEvents)
+                throws CacheEntryListenerException {
+            for (final CacheEntryEvent<? extends String, ? extends String> cacheEntryEvent : cacheEntryEvents) {
+                events.add(cacheEntryEvent);
+            }
+        }
+    }
+}

-- 
To stop receiving notification emails like this one, please contact
rmannibucau@apache.org.