[ 
https://issues.apache.org/jira/browse/OAK-4263?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15251618#comment-15251618
 ] 

Thomas Mueller commented on OAK-4263:
-------------------------------------

Possible patch (uses an AtomicBoolean):

{noformat}
===================================================================
--- src/main/java/org/apache/jackrabbit/oak/cache/CacheLIRS.java        
(revision 1738734)
+++ src/main/java/org/apache/jackrabbit/oak/cache/CacheLIRS.java        
(working copy)
@@ -27,6 +27,7 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import javax.annotation.Nonnull;
@@ -74,9 +75,13 @@
  */
 public class CacheLIRS<K, V> implements LoadingCache<K, V> {
 
-    private static final Logger LOG = LoggerFactory.getLogger(CacheLIRS.class);
+    static final Logger LOG = LoggerFactory.getLogger(CacheLIRS.class);
+    static final ThreadLocal<Integer> CURRENTLY_LOADING = new 
ThreadLocal<Integer>();
     private static final AtomicInteger NEXT_CACHE_ID = new AtomicInteger();
-    private static final ThreadLocal<Integer> CURRENTLY_LOADING = new 
ThreadLocal<Integer>();
+    
+    static {
+        LOG.info("CacheLIRS with less notifyAll");
+    }
 
     /**
      * Listener for items that are evicted from the cache. The listener
@@ -104,7 +109,7 @@
         void evicted(@Nonnull K key, @Nullable V value, @Nonnull RemovalCause 
cause);
     }
     
-    private final int cacheId = NEXT_CACHE_ID.getAndIncrement();
+    final int cacheId = NEXT_CACHE_ID.getAndIncrement();
 
     /**
      * The maximum memory this cache should use.
@@ -138,8 +143,8 @@
      * value to be loaded need to wait on the synchronization object. The
      * loading thread will notify all waiting threads once loading is done.
      */
-    final ConcurrentHashMap<K, Object> loadingInProgress =
-            new ConcurrentHashMap<K, Object>();
+    final ConcurrentHashMap<K, AtomicBoolean> loadingInProgress =
+            new ConcurrentHashMap<K, AtomicBoolean>();
 
     /**
      * Create a new cache with the given number of entries, and the default
@@ -952,14 +957,14 @@
                     // to prevent a deadlock, we also load the value ourselves
                     return load(key, hash, valueLoader);
                 }
-                ConcurrentHashMap<K, Object> loading = cache.loadingInProgress;
+                ConcurrentHashMap<K, AtomicBoolean> loading = 
cache.loadingInProgress;
                 // the object we have to wait for in case another thread loads
                 // this value
-                Object alreadyLoading;
+                AtomicBoolean alreadyLoading;
                 // synchronized on this object, even before we put it in the
                 // cache, so that all other threads that get this object can
                 // synchronized and wait for it
-                Object loadNow = new Object();
+                AtomicBoolean loadNow = new AtomicBoolean();
                 // we synchronize a bit early here, but that's fine (we don't
                 // optimize for the case where loading is extremely quick)
                 synchronized (loadNow) {
@@ -971,16 +976,20 @@
                             return load(key, hash, valueLoader);
                         } finally {
                             loading.remove(key);
-                            // notify other threads
-                            loadNow.notifyAll();
+                            if (loadNow.get()) {
+                                // notify other threads, but only if
+                                // they wait for this to be loaded
+                                loadNow.notifyAll();
+                            }
                             CURRENTLY_LOADING.remove();
                         }
                     }
                 }
                 // another thread is (or was) already loading
                 synchronized (alreadyLoading) {
+                    alreadyLoading.set(true);
                     // loading might have been finished, so check again
-                    Object alreadyLoading2 = loading.get(key);
+                    AtomicBoolean alreadyLoading2 = loading.get(key);
                     if (alreadyLoading2 != alreadyLoading) {
                         // loading has completed before we could synchronize,
                         // so we repeat

{noformat}

> LIRS cache: excessive use of notifyAll
> --------------------------------------
>
>                 Key: OAK-4263
>                 URL: https://issues.apache.org/jira/browse/OAK-4263
>             Project: Jackrabbit Oak
>          Issue Type: Bug
>            Reporter: Thomas Mueller
>            Assignee: Thomas Mueller
>             Fix For: 1.6
>
>
> The LIRS cache tries to avoid loading the same cache entry concurrently. To 
> notify a possible waiting thread, it uses notifyAll. This is a relatively 
> expensive operation, and should be avoided if possible.



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to