You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ju...@apache.org on 2010/09/28 11:20:01 UTC

svn commit: r1002066 - /jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/MLRUItemStateCache.java

Author: jukka
Date: Tue Sep 28 09:20:01 2010
New Revision: 1002066

URL: http://svn.apache.org/viewvc?rev=1002066&view=rev
Log:
JCR-2699: Improve read/write concurrency

Use a LinkedHashMap instead of LinkedMap from Commons Collections to optimize the LRU data structure.

Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/MLRUItemStateCache.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/MLRUItemStateCache.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/MLRUItemStateCache.java?rev=1002066&r1=1002065&r2=1002066&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/MLRUItemStateCache.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/MLRUItemStateCache.java Tue Sep 28 09:20:01 2010
@@ -16,7 +16,10 @@
  */
 package org.apache.jackrabbit.core.state;
 
-import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
 
 import org.apache.commons.collections.map.LinkedMap;
 import org.apache.jackrabbit.core.id.ItemId;
@@ -41,16 +44,16 @@ public class MLRUItemStateCache implemen
     public static final int DEFAULT_MAX_MEM = 4 * 1024 * 1024;
 
     /** the amount of memory the entries use */
-    private long totalMem;
+    private volatile long totalMem;
 
     /** the maximum of memory the cache may use */
-    private long maxMem;
+    private volatile long maxMem;
 
     /** the number of writes */
-    private long numWrites;
+    private volatile long numWrites;
 
     /** the access count */
-    private long accessCount;
+    private volatile long accessCount;
 
     /** the cache access listeners */
     private CacheAccessListener accessListener;
@@ -58,7 +61,7 @@ public class MLRUItemStateCache implemen
     /**
      * A cache for <code>ItemState</code> instances
      */
-    private final LinkedMap cache = new LinkedMap();
+    private final Map<ItemId, Entry> cache;
 
     /**
      * Constructs a new, empty <code>ItemStateCache</code> with a maximum amount
@@ -74,8 +77,21 @@ public class MLRUItemStateCache implemen
      *
      * @param maxMem the maximum amount of memory this cache may use.
      */
+    @SuppressWarnings("serial")
     private MLRUItemStateCache(int maxMem) {
         this.maxMem = maxMem;
+        this.cache = new LinkedHashMap<ItemId, MLRUItemStateCache.Entry>(
+                maxMem / 1024, 0.75f, true /* access-ordered */) {
+            @Override
+            protected boolean removeEldestEntry(Map.Entry<ItemId, Entry> e) {
+                if (totalMem > MLRUItemStateCache.this.maxMem) {
+                    totalMem -= e.getValue().size;
+                    return true;
+                } else {
+                    return false;
+                }
+            }
+        };
     }
 
     //-------------------------------------------------------< ItemStateCache >
@@ -94,10 +110,8 @@ public class MLRUItemStateCache implemen
     public ItemState retrieve(ItemId id) {
         touch();
         synchronized (cache) {
-            Entry entry = (Entry) cache.remove(id);
+            Entry entry = cache.get(id);
             if (entry != null) {
-                // 'touch' item, by adding at end of list
-                cache.put(id, entry);
                 return entry.state;
             } else {
                 return null;
@@ -110,7 +124,12 @@ public class MLRUItemStateCache implemen
      */
     public ItemState[] retrieveAll() {
         synchronized (cache) {
-            return (ItemState[]) cache.values().toArray(new ItemState[cache.size()]);
+            ItemState[] states = new ItemState[cache.size()];
+            int i = 0;
+            for (Entry entry : cache.values()) {
+                states[i++] = entry.state;
+            }
+            return states;
         }
     }
 
@@ -120,7 +139,7 @@ public class MLRUItemStateCache implemen
     public void update(ItemId id) {
         touch();
         synchronized (cache) {
-            Entry entry = (Entry) cache.get(id);
+            Entry entry = cache.get(id);
             if (entry != null) {
                 totalMem -= entry.size;
                 entry.recalc();
@@ -141,33 +160,21 @@ public class MLRUItemStateCache implemen
                 evict(id);
             }
             Entry entry = new Entry(state);
-            cache.put(id, entry);
             totalMem += entry.size;
-            shrinkIfRequired();
+            cache.put(id, entry);
             if (numWrites++ % 10000 == 0 && log.isDebugEnabled()) {
                 log.debug(this + " size=" + cache.size() + ", " + totalMem + "/" + maxMem);
             }
         }
     }
 
-    private void shrinkIfRequired() {
-        // remove items, if too many
-        synchronized (cache) {
-            while (totalMem > maxMem) {
-                ItemId id = (ItemId) cache.firstKey();
-                Entry entry = (Entry) cache.remove(id);
-                totalMem -= entry.size;
-            }
-        }
-    }
-
     /**
      * {@inheritDoc}
      */
     public void evict(ItemId id) {
         touch();
         synchronized (cache) {
-            Entry entry = (Entry) cache.remove(id);
+            Entry entry = cache.remove(id);
             if (entry != null) {
                 totalMem -= entry.size;
             }
@@ -220,15 +227,6 @@ public class MLRUItemStateCache implemen
      * {@inheritDoc}
      */
     public long getMemoryUsed() {
-        synchronized (cache) {
-            totalMem = 0;
-            Iterator iter = cache.values().iterator();
-            while (iter.hasNext()) {
-                Entry entry = (Entry) iter.next();
-                entry.recalc();
-                totalMem += entry.size;
-            }
-        }
         return totalMem;
     }
 
@@ -247,7 +245,21 @@ public class MLRUItemStateCache implemen
     public void setMaxMemorySize(long size) {
         synchronized (cache) {
             this.maxMem = size;
-            shrinkIfRequired();
+
+            // remove items, if too many
+            if (totalMem > maxMem) {
+                totalMem = 0;
+                List<Map.Entry<ItemId, Entry>> entries =
+                    new ArrayList<Map.Entry<ItemId, Entry>>(cache.entrySet());
+                for (Map.Entry<ItemId, Entry> entry : entries) {
+                    long entrySize = entry.getValue().size;
+                    if (totalMem + entrySize > maxMem) {
+                        cache.remove(entry.getKey());
+                    } else {
+                        totalMem += entrySize;
+                    }
+                }
+            }
         }
     }