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/10/21 17:13:34 UTC

svn commit: r1026025 - in /jackrabbit/branches/2.0: ./ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cache/ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/ jackrabbit-core/src/main/java/org/apache/jackrabbit/core...

Author: jukka
Date: Thu Oct 21 15:13:34 2010
New Revision: 1026025

URL: http://svn.apache.org/viewvc?rev=1026025&view=rev
Log:
2.0: Merged revisions 1025990 and 1025995 (JCR-2699)

Added:
    jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cache/AbstractCache.java
      - copied unchanged from r1025990, jackrabbit/branches/2.1/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cache/AbstractCache.java
    jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cache/ConcurrentCache.java
      - copied, changed from r1025990, jackrabbit/branches/2.1/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cache/ConcurrentCache.java
    jackrabbit/branches/2.0/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cache/
      - copied from r1025990, jackrabbit/branches/2.1/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cache/
    jackrabbit/branches/2.0/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cache/ConcurrentCacheTest.java
      - copied unchanged from r1025990, jackrabbit/branches/2.1/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cache/ConcurrentCacheTest.java
Removed:
    jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/util/BundleCache.java
    jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/util/LRUNodeIdCache.java
Modified:
    jackrabbit/branches/2.0/   (props changed)
    jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/AbstractBundlePersistenceManager.java
    jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/BundleDbPersistenceManager.java
    jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/BundleFsPersistenceManager.java
    jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/AbstractBundlePersistenceManager.java
    jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/BundleDbPersistenceManager.java
    jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/BundleFsPersistenceManager.java
    jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/PostgreSQLPersistenceManager.java
    jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/ItemStateCache.java
    jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/ItemStateReferenceCache.java
    jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/LocalItemStateManager.java
    jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/MLRUItemStateCache.java
    jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/ManagedMLRUItemStateCacheFactory.java
    jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java

Propchange: jackrabbit/branches/2.0/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Thu Oct 21 15:13:34 2010
@@ -1,6 +1,6 @@
 /jackrabbit/branches/1.5:794012,794100,794102
-/jackrabbit/branches/2.1:955309,955314,982266,982277,982505,998310,1025933,1025957,1025962,1025964,1025981,1025985
+/jackrabbit/branches/2.1:955309,955314,982266,982277,982505,998310,1025933,1025957,1025962,1025964,1025981,1025985,1025990,1025995
 /jackrabbit/sandbox/JCR-1456:774917-886178
 /jackrabbit/sandbox/JCR-2170:812417-816332
 /jackrabbit/sandbox/tripod-JCR-2209:795441-795863
-/jackrabbit/trunk:891595,891629,892253,892263,894150-894151,896408,896513,896532,896857,896870,896876,896908,896940,896942-896943,896969,896977,897071,897836,897842,897858,897935,897983,897992-897993,897996,898002,898042,898267,898325,898540,898677,898699,898701,898715,898872,899102,899181,899391,899393-899394,899583,899594,899643,900305,900310,900314,900453,900702,900736,900762-900763,900767,900782,901095,901122,901139,901144,901170,901176,901191,901193,901196,901216,901228,901285,902058,902062,926324,928888,936668,955222,955229,955307,955852,965539,996810,1001707,1002065-1002066,1002084,1002101-1002102,1002168,1002170,1002589,1002608,1002657,1002729,1003423,1003470
+/jackrabbit/trunk:891595,891629,892253,892263,894150-894151,896408,896513,896532,896857,896870,896876,896908,896940,896942-896943,896969,896977,897071,897836,897842,897858,897935,897983,897992-897993,897996,898002,898042,898267,898325,898540,898677,898699,898701,898715,898872,899102,899181,899391,899393-899394,899583,899594,899643,900305,900310,900314,900453,900702,900736,900762-900763,900767,900782,901095,901122,901139,901144,901170,901176,901191,901193,901196,901216,901228,901285,902058,902062,926324,928888,936668,955222,955229,955307,955852,965539,996810,1001707,1002065-1002066,1002084,1002101-1002102,1002168,1002170,1002589,1002608,1002657,1002729,1003423,1003470,1003542,1003773,1004182,1004184,1004223-1004224

Copied: jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cache/ConcurrentCache.java (from r1025990, jackrabbit/branches/2.1/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cache/ConcurrentCache.java)
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cache/ConcurrentCache.java?p2=jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cache/ConcurrentCache.java&p1=jackrabbit/branches/2.1/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cache/ConcurrentCache.java&r1=1025990&r2=1026025&rev=1026025&view=diff
==============================================================================
--- jackrabbit/branches/2.1/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cache/ConcurrentCache.java (original)
+++ jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cache/ConcurrentCache.java Thu Oct 21 15:13:34 2010
@@ -22,9 +22,6 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 /**
  * Concurrent cache implementation that uses cache segments to minimize
  * the chance of lock contention. The LRU algorithm is used to evict excess
@@ -34,9 +31,6 @@ import org.slf4j.LoggerFactory;
  */
 public class ConcurrentCache<K, V> extends AbstractCache {
 
-    /** Logger instance */
-    private static Logger log = LoggerFactory.getLogger(ConcurrentCache.class);
-
     private static class E<V> {
 
         private final V value;
@@ -150,16 +144,18 @@ public class ConcurrentCache<K, V> exten
      * @param key entry key
      * @param value entry value
      * @param size entry size
+     * @return the previous value, or <code>null</code>
      */
-    public void put(K key, V value, long size) {
+    public V put(K key, V value, long size) {
         Map<K, E<V>> segment = getSegment(key);
         synchronized (segment) {
             recordSizeChange(size);
             E<V> previous = segment.put(key, new E<V>(value, size));
             if (previous != null) {
-                log.warn("Overwriting cached entry {} from {} to {}",
-                        new Object[] { key, previous.value, value });
                 recordSizeChange(-previous.size);
+                return previous.value;
+            } else {
+                return null;
             }
         }
     }

Modified: jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/AbstractBundlePersistenceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/AbstractBundlePersistenceManager.java?rev=1026025&r1=1026024&r2=1026025&view=diff
==============================================================================
--- jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/AbstractBundlePersistenceManager.java (original)
+++ jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/AbstractBundlePersistenceManager.java Thu Oct 21 15:13:34 2010
@@ -18,6 +18,7 @@ package org.apache.jackrabbit.core.persi
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.apache.jackrabbit.core.cache.ConcurrentCache;
 import org.apache.jackrabbit.core.fs.FileSystemResource;
 import org.apache.jackrabbit.core.fs.FileSystem;
 import org.apache.jackrabbit.core.state.ItemState;
@@ -37,9 +38,7 @@ import org.apache.jackrabbit.core.persis
 import org.apache.jackrabbit.core.persistence.PersistenceManager;
 import org.apache.jackrabbit.core.persistence.util.BundleBinding;
 import org.apache.jackrabbit.core.util.StringIndex;
-import org.apache.jackrabbit.core.persistence.util.BundleCache;
 import org.apache.jackrabbit.core.persistence.util.HashMapIndex;
-import org.apache.jackrabbit.core.persistence.util.LRUNodeIdCache;
 import org.apache.jackrabbit.core.persistence.util.NodePropBundle;
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.commons.name.NameConstants;
@@ -68,7 +67,7 @@ import javax.jcr.PropertyType;
  * included in the bundle but generated when required.
  * <p/>
  * In order to increase performance, there are 2 caches maintained. One is the
- * {@link BundleCache} that caches already loaded bundles. The other is the
+ * bundle cache that caches already loaded bundles. The other is the
  * {@link LRUNodeIdCache} that caches non-existent bundles. This is useful
  * because a lot of {@link #exists(NodeId)} calls are issued that would result
  * in a useless SQL execution if the desired bundle does not exist.
@@ -96,6 +95,10 @@ public abstract class AbstractBundlePers
     /** the name of the namespace-index resource */
     protected static final String RES_NS_INDEX = "/namespaces.properties";
 
+    /** Sentinel instance used to mark a non-existent bundle in the cache */
+    private static final NodePropBundle MISSING =
+        new NodePropBundle(null, new NodeId());
+
     /** the index for namespaces */
     private StringIndex nsIndex;
 
@@ -103,10 +106,7 @@ public abstract class AbstractBundlePers
     private StringIndex nameIndex;
 
     /** the cache of loaded bundles */
-    private BundleCache bundles;
-
-    /** the cache of non-existent bundles */
-    private LRUNodeIdCache missing;
+    private ConcurrentCache<NodeId, NodePropBundle> bundles;
 
     /** the persistence manager context */
     protected PMContext context;
@@ -286,25 +286,22 @@ public abstract class AbstractBundlePers
      */
     public synchronized void onExternalUpdate(ChangeLog changes) {
         for (ItemState state : changes.modifiedStates()) {
-            if (state.isNode()) {
-                bundles.remove((NodeId) state.getId());
-            } else {
-                bundles.remove(state.getParentId());
-            }
+            bundles.remove(getBundleId(state));
         }
         for (ItemState state : changes.deletedStates()) {
-            if (state.isNode()) {
-                bundles.remove((NodeId) state.getId());
-            } else {
-                bundles.remove(state.getParentId());
-            }
+            bundles.remove(getBundleId(state));
         }
         for (ItemState state : changes.addedStates()) {
-            if (state.isNode()) {
-                missing.remove((NodeId) state.getId());
-            } else {
-                missing.remove(state.getParentId());
-            }
+            // There may have been a cache miss entry
+            bundles.remove(getBundleId(state));
+        }
+    }
+
+    private NodeId getBundleId(ItemState state) {
+        if (state.isNode()) {
+            return (NodeId) state.getId();
+        } else {
+            return state.getParentId();
         }
     }
 
@@ -322,17 +319,6 @@ public abstract class AbstractBundlePers
             throws ItemStateException;
 
     /**
-     * Checks if a bundle exists in the underlying system.
-     *
-     * @param id the node id of the bundle
-     * @return <code>true</code> if the bundle exists;
-     *         <code>false</code> otherwise.
-     * @throws ItemStateException if an error while checking occurs.
-     */
-    protected abstract boolean existsBundle(NodeId id)
-            throws ItemStateException;
-
-    /**
      * Stores a bundle to the underlying system.
      *
      * @param bundle the bundle to store
@@ -385,8 +371,8 @@ public abstract class AbstractBundlePers
     public void init(PMContext context) throws Exception {
         this.context = context;
         // init bundle cache
-        bundles = new BundleCache(bundleCacheSize);
-        missing = new LRUNodeIdCache();
+        bundles = new ConcurrentCache<NodeId, NodePropBundle>();
+        bundles.setMaxMemorySize(bundleCacheSize);
     }
     
     /**
@@ -397,7 +383,6 @@ public abstract class AbstractBundlePers
     public void close() throws Exception {
         // clear caches
         bundles.clear();
-        missing.clear();
     }
 
     /**
@@ -504,7 +489,6 @@ public abstract class AbstractBundlePers
         } finally {
             if (!success) {
                 bundles.clear();
-                missing.clear();
             }
         }
     }
@@ -637,7 +621,9 @@ public abstract class AbstractBundlePers
     }
 
     /**
-     * Gets the bundle for the given node id.
+     * Gets the bundle for the given node id. Read/write synchronization
+     * happens higher up at the SISM level, so we don't need to worry about
+     * conflicts here.
      *
      * @param id the id of the bundle to retrieve.
      * @return the bundle or <code>null</code> if the bundle does not exist
@@ -645,19 +631,16 @@ public abstract class AbstractBundlePers
      * @throws ItemStateException if an error occurs.
      */
     private NodePropBundle getBundle(NodeId id) throws ItemStateException {
-        if (missing.contains(id)) {
-            return null;
-        }
         NodePropBundle bundle = bundles.get(id);
-        if (bundle == null) {
-            synchronized (this) {
-                bundle = loadBundle(id);
-                if (bundle != null) {
-                    bundle.markOld();
-                    bundles.put(bundle);
-                } else {
-                    missing.put(id);
-                }
+        if (bundle == MISSING) {
+            return null;
+        } else if (bundle == null) {
+            bundle = loadBundle(id);
+            if (bundle != null) {
+                bundle.markOld();
+                bundles.put(id, bundle, bundle.getSize());
+            } else {
+                bundles.put(id, MISSING, 16);
             }
         }
         return bundle;
@@ -672,8 +655,7 @@ public abstract class AbstractBundlePers
     private void deleteBundle(NodePropBundle bundle) throws ItemStateException {
         destroyBundle(bundle);
         bundle.removeAllProperties();
-        bundles.remove(bundle.getId());
-        missing.put(bundle.getId());
+        bundles.put(bundle.getId(), MISSING, 16);
     }
 
     /**
@@ -687,11 +669,10 @@ public abstract class AbstractBundlePers
         bundle.markOld();
         log.debug("stored bundle {}", bundle.getId());
 
-        missing.remove(bundle.getId());
         // only put to cache if already exists. this is to ensure proper overwrite
         // and not creating big contention during bulk loads
-        if (bundles.contains(bundle.getId())) {
-            bundles.put(bundle);
+        if (bundles.containsKey(bundle.getId())) {
+            bundles.put(bundle.getId(), bundle, bundle.getSize());
         }
     }
 

Modified: jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/BundleDbPersistenceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/BundleDbPersistenceManager.java?rev=1026025&r1=1026024&r2=1026025&view=diff
==============================================================================
--- jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/BundleDbPersistenceManager.java (original)
+++ jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/BundleDbPersistenceManager.java Thu Oct 21 15:13:34 2010
@@ -779,7 +779,7 @@ public class BundleDbPersistenceManager 
         try {
             // skip root nodes (that point to itself)
             if (parentId != null && !id.toString().endsWith("babecafebabe")) {
-                if (!existsBundle(parentId)) {
+                if (loadBundle(parentId) == null) {
                     log.error("NodeState '" + id + "' references inexistent parent uuid '" + parentId + "'");
                 }
             }
@@ -1176,25 +1176,6 @@ public class BundleDbPersistenceManager 
     /**
      * {@inheritDoc}
      */
-    protected synchronized boolean existsBundle(NodeId id) throws ItemStateException {
-        ResultSet rs = null;
-        try {
-            Statement stmt = connectionManager.executeStmt(bundleSelectSQL, getKey(id));
-            rs = stmt.getResultSet();
-            // a bundle exists, if the result has at least one entry
-            return rs.next();
-        } catch (Exception e) {
-            String msg = "failed to check existence of bundle: " + id;
-            log.error(msg, e);
-            throw new ItemStateException(msg, e);
-        } finally {
-            closeResultSet(rs);
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
     protected synchronized void storeBundle(NodePropBundle bundle) throws ItemStateException {
         try {
             ByteArrayOutputStream out = new ByteArrayOutputStream(INITIAL_BUFFER_SIZE);

Modified: jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/BundleFsPersistenceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/BundleFsPersistenceManager.java?rev=1026025&r1=1026024&r2=1026025&view=diff
==============================================================================
--- jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/BundleFsPersistenceManager.java (original)
+++ jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/BundleFsPersistenceManager.java Thu Oct 21 15:13:34 2010
@@ -232,8 +232,7 @@ public class BundleFsPersistenceManager 
     /**
      * {@inheritDoc}
      */
-    protected synchronized NodePropBundle loadBundle(NodeId id)
-            throws ItemStateException {
+    protected NodePropBundle loadBundle(NodeId id) throws ItemStateException {
         DataInputStream din = null;
         try {
             String path = buildNodeFilePath(null, id).toString();
@@ -256,20 +255,6 @@ public class BundleFsPersistenceManager 
     }
 
     /**
-     * {@inheritDoc}
-     */
-    protected synchronized boolean existsBundle(NodeId id) throws ItemStateException {
-        try {
-            StringBuffer buf = buildNodeFilePath(null, id);
-            return itemFs.exists(buf.toString());
-        } catch (Exception e) {
-            String msg = "failed to check existence of bundle: " + id;
-            BundleFsPersistenceManager.log.error(msg, e);
-            throw new ItemStateException(msg, e);
-        }
-    }
-
-    /**
      * Creates the file path for the given node id that is
      * suitable for storing node states in a filesystem.
      *

Modified: jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/AbstractBundlePersistenceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/AbstractBundlePersistenceManager.java?rev=1026025&r1=1026024&r2=1026025&view=diff
==============================================================================
--- jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/AbstractBundlePersistenceManager.java (original)
+++ jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/AbstractBundlePersistenceManager.java Thu Oct 21 15:13:34 2010
@@ -24,6 +24,7 @@ import javax.jcr.PropertyType;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.apache.jackrabbit.core.cache.ConcurrentCache;
 import org.apache.jackrabbit.core.fs.FileSystemResource;
 import org.apache.jackrabbit.core.fs.FileSystem;
 import org.apache.jackrabbit.core.id.ItemId;
@@ -34,9 +35,7 @@ import org.apache.jackrabbit.core.persis
 import org.apache.jackrabbit.core.persistence.PMContext;
 import org.apache.jackrabbit.core.persistence.PersistenceManager;
 import org.apache.jackrabbit.core.persistence.util.BundleBinding;
-import org.apache.jackrabbit.core.persistence.util.BundleCache;
 import org.apache.jackrabbit.core.persistence.util.HashMapIndex;
-import org.apache.jackrabbit.core.persistence.util.LRUNodeIdCache;
 import org.apache.jackrabbit.core.persistence.util.NodePropBundle;
 import org.apache.jackrabbit.core.state.ItemState;
 import org.apache.jackrabbit.core.state.ChangeLog;
@@ -68,7 +67,7 @@ import org.apache.jackrabbit.spi.commons
  * included in the bundle but generated when required.
  * <p/>
  * In order to increase performance, there are 2 caches maintained. One is the
- * {@link BundleCache} that caches already loaded bundles. The other is the
+ * bundle cache that caches already loaded bundles. The other is the
  * {@link LRUNodeIdCache} that caches non-existent bundles. This is useful
  * because a lot of {@link #exists(NodeId)} calls are issued that would result
  * in a useless SQL execution if the desired bundle does not exist.
@@ -96,6 +95,10 @@ public abstract class AbstractBundlePers
     /** the name of the namespace-index resource */
     protected static final String RES_NS_INDEX = "/namespaces.properties";
 
+    /** Sentinel instance used to mark a non-existent bundle in the cache */
+    private static final NodePropBundle MISSING =
+        new NodePropBundle(null, new NodeId());
+
     /** the index for namespaces */
     private StringIndex nsIndex;
 
@@ -103,10 +106,7 @@ public abstract class AbstractBundlePers
     private StringIndex nameIndex;
 
     /** the cache of loaded bundles */
-    private BundleCache bundles;
-
-    /** the cache of non-existent bundles */
-    private LRUNodeIdCache missing;
+    private ConcurrentCache<NodeId, NodePropBundle> bundles;
 
     /** the persistence manager context */
     protected PMContext context;
@@ -286,25 +286,22 @@ public abstract class AbstractBundlePers
      */
     public synchronized void onExternalUpdate(ChangeLog changes) {
         for (ItemState state : changes.modifiedStates()) {
-            if (state.isNode()) {
-                bundles.remove((NodeId) state.getId());
-            } else {
-                bundles.remove(state.getParentId());
-            }
+            bundles.remove(getBundleId(state));
         }
         for (ItemState state : changes.deletedStates()) {
-            if (state.isNode()) {
-                bundles.remove((NodeId) state.getId());
-            } else {
-                bundles.remove(state.getParentId());
-            }
+            bundles.remove(getBundleId(state));
         }
         for (ItemState state : changes.addedStates()) {
-            if (state.isNode()) {
-                missing.remove((NodeId) state.getId());
-            } else {
-                missing.remove(state.getParentId());
-            }
+            // There may have been a cache miss entry
+            bundles.remove(getBundleId(state));
+        }
+    }
+
+    private NodeId getBundleId(ItemState state) {
+        if (state.isNode()) {
+            return (NodeId) state.getId();
+        } else {
+            return state.getParentId();
         }
     }
 
@@ -322,17 +319,6 @@ public abstract class AbstractBundlePers
             throws ItemStateException;
 
     /**
-     * Checks if a bundle exists in the underlying system.
-     *
-     * @param id the node id of the bundle
-     * @return <code>true</code> if the bundle exists;
-     *         <code>false</code> otherwise.
-     * @throws ItemStateException if an error while checking occurs.
-     */
-    protected abstract boolean existsBundle(NodeId id)
-            throws ItemStateException;
-
-    /**
      * Stores a bundle to the underlying system.
      *
      * @param bundle the bundle to store
@@ -385,19 +371,18 @@ public abstract class AbstractBundlePers
     public void init(PMContext context) throws Exception {
         this.context = context;
         // init bundle cache
-        bundles = new BundleCache(bundleCacheSize);
-        missing = new LRUNodeIdCache();
+        bundles = new ConcurrentCache<NodeId, NodePropBundle>();
+        bundles.setMaxMemorySize(bundleCacheSize);
     }
 
     /**
      * {@inheritDoc}
      *
-     *  Closes the persistence manager, release acquired resourecs.
+     *  Closes the persistence manager, release acquired resources.
      */
     public void close() throws Exception {
         // clear caches
         bundles.clear();
-        missing.clear();
     }
 
     /**
@@ -502,7 +487,6 @@ public abstract class AbstractBundlePers
         } finally {
             if (!success) {
                 bundles.clear();
-                missing.clear();
             }
         }
     }
@@ -635,7 +619,9 @@ public abstract class AbstractBundlePers
     }
 
     /**
-     * Gets the bundle for the given node id.
+     * Gets the bundle for the given node id. Read/write synchronization
+     * happens higher up at the SISM level, so we don't need to worry about
+     * conflicts here.
      *
      * @param id the id of the bundle to retrieve.
      * @return the bundle or <code>null</code> if the bundle does not exist
@@ -643,19 +629,16 @@ public abstract class AbstractBundlePers
      * @throws ItemStateException if an error occurs.
      */
     private NodePropBundle getBundle(NodeId id) throws ItemStateException {
-        if (missing.contains(id)) {
-            return null;
-        }
         NodePropBundle bundle = bundles.get(id);
-        if (bundle == null) {
-            synchronized (this) {
-                bundle = loadBundle(id);
-                if (bundle != null) {
-                    bundle.markOld();
-                    bundles.put(bundle);
-                } else {
-                    missing.put(id);
-                }
+        if (bundle == MISSING) {
+            return null;
+        } else if (bundle == null) {
+            bundle = loadBundle(id);
+            if (bundle != null) {
+                bundle.markOld();
+                bundles.put(id, bundle, bundle.getSize());
+            } else {
+                bundles.put(id, MISSING, 16);
             }
         }
         return bundle;
@@ -670,8 +653,7 @@ public abstract class AbstractBundlePers
     private void deleteBundle(NodePropBundle bundle) throws ItemStateException {
         destroyBundle(bundle);
         bundle.removeAllProperties();
-        bundles.remove(bundle.getId());
-        missing.put(bundle.getId());
+        bundles.put(bundle.getId(), MISSING, 16);
     }
 
     /**
@@ -685,11 +667,10 @@ public abstract class AbstractBundlePers
         bundle.markOld();
         log.debug("stored bundle {}", bundle.getId());
 
-        missing.remove(bundle.getId());
-        // only put to cache if already exists. this is to ensure proper overwrite
-        // and not creating big contention during bulk loads
-        if (bundles.contains(bundle.getId())) {
-            bundles.put(bundle);
+        // only put to cache if already exists. this is to ensure proper
+        // overwrite and not creating big contention during bulk loads
+        if (bundles.containsKey(bundle.getId())) {
+            bundles.put(bundle.getId(), bundle, bundle.getSize());
         }
     }
 

Modified: jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/BundleDbPersistenceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/BundleDbPersistenceManager.java?rev=1026025&r1=1026024&r2=1026025&view=diff
==============================================================================
--- jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/BundleDbPersistenceManager.java (original)
+++ jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/BundleDbPersistenceManager.java Thu Oct 21 15:13:34 2010
@@ -744,7 +744,7 @@ public class BundleDbPersistenceManager 
         try {
             // skip root nodes (that point to itself)
             if (parentId != null && !id.toString().endsWith("babecafebabe")) {
-                if (!existsBundle(parentId)) {
+                if (loadBundle(parentId) == null) {
                     log.error("NodeState '" + id + "' references inexistent parent uuid '" + parentId + "'");
                 }
             }
@@ -1024,8 +1024,7 @@ public class BundleDbPersistenceManager 
     /**
      * {@inheritDoc}
      */
-    protected synchronized NodePropBundle loadBundle(NodeId id)
-            throws ItemStateException {
+    protected NodePropBundle loadBundle(NodeId id) throws ItemStateException {
         return loadBundle(id, false);
     }
 
@@ -1064,7 +1063,7 @@ public class BundleDbPersistenceManager 
      *         exist.
      * @throws ItemStateException if an error while loading occurs.
      */
-    protected synchronized NodePropBundle loadBundle(NodeId id, boolean checkBeforeLoading)
+    protected NodePropBundle loadBundle(NodeId id, boolean checkBeforeLoading)
             throws ItemStateException {
         ResultSet rs = null;
         
@@ -1102,24 +1101,6 @@ public class BundleDbPersistenceManager 
     /**
      * {@inheritDoc}
      */
-    protected synchronized boolean existsBundle(NodeId id) throws ItemStateException {
-        ResultSet rs = null;
-        try {
-            rs = conHelper.exec(bundleSelectSQL, getKey(id), false, 0);
-            // a bundle exists, if the result has at least one entry
-            return rs.next();
-        } catch (Exception e) {
-            String msg = "failed to check existence of bundle: " + id;
-            log.error(msg, e);
-            throw new ItemStateException(msg, e);
-        } finally {
-            DbUtility.close(rs);
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
     protected synchronized void storeBundle(NodePropBundle bundle) throws ItemStateException {
         try {
             ByteArrayOutputStream out = new ByteArrayOutputStream(INITIAL_BUFFER_SIZE);

Modified: jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/BundleFsPersistenceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/BundleFsPersistenceManager.java?rev=1026025&r1=1026024&r2=1026025&view=diff
==============================================================================
--- jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/BundleFsPersistenceManager.java (original)
+++ jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/BundleFsPersistenceManager.java Thu Oct 21 15:13:34 2010
@@ -231,8 +231,7 @@ public class BundleFsPersistenceManager 
     /**
      * {@inheritDoc}
      */
-    protected synchronized NodePropBundle loadBundle(NodeId id)
-            throws ItemStateException {
+    protected NodePropBundle loadBundle(NodeId id) throws ItemStateException {
         DataInputStream din = null;
         try {
             String path = buildNodeFilePath(null, id).toString();
@@ -255,20 +254,6 @@ public class BundleFsPersistenceManager 
     }
 
     /**
-     * {@inheritDoc}
-     */
-    protected synchronized boolean existsBundle(NodeId id) throws ItemStateException {
-        try {
-            StringBuffer buf = buildNodeFilePath(null, id);
-            return itemFs.exists(buf.toString());
-        } catch (Exception e) {
-            String msg = "failed to check existence of bundle: " + id;
-            BundleFsPersistenceManager.log.error(msg, e);
-            throw new ItemStateException(msg, e);
-        }
-    }
-
-    /**
      * Creates the file path for the given node id that is
      * suitable for storing node states in a filesystem.
      *

Modified: jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/PostgreSQLPersistenceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/PostgreSQLPersistenceManager.java?rev=1026025&r1=1026024&r2=1026025&view=diff
==============================================================================
--- jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/PostgreSQLPersistenceManager.java (original)
+++ jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/pool/PostgreSQLPersistenceManager.java Thu Oct 21 15:13:34 2010
@@ -92,10 +92,9 @@ public class PostgreSQLPersistenceManage
      * 
      * {@inheritDoc}
      */
-    protected synchronized NodePropBundle loadBundle(NodeId id)
-            throws ItemStateException {
+    protected NodePropBundle loadBundle(NodeId id) throws ItemStateException {
         ResultSet rs = null;
-        try {        	
+        try {
             rs = conHelper.exec(bundleSelectSQL, getKey(id), false, 0);
             if (rs.next()) {
                 InputStream input = rs.getBinaryStream(1);

Modified: jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/ItemStateCache.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/ItemStateCache.java?rev=1026025&r1=1026024&r2=1026025&view=diff
==============================================================================
--- jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/ItemStateCache.java (original)
+++ jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/ItemStateCache.java Thu Oct 21 15:13:34 2010
@@ -83,14 +83,6 @@ public interface ItemStateCache {
     boolean isEmpty();
 
     /**
-     * Informs the cache that the item was modified and the cache might need to
-     * recalculate the items caching weight.
-     *
-     * @param id the id of the item that was modified.
-     */
-    void update(ItemId id);
-
-    /**
      * Informs the cache that it is no longer in use.
      */
     void dispose();

Modified: jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/ItemStateReferenceCache.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/ItemStateReferenceCache.java?rev=1026025&r1=1026024&r2=1026025&view=diff
==============================================================================
--- jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/ItemStateReferenceCache.java (original)
+++ jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/ItemStateReferenceCache.java Thu Oct 21 15:13:34 2010
@@ -18,11 +18,11 @@ package org.apache.jackrabbit.core.state
 
 import org.apache.commons.collections.map.ReferenceMap;
 import org.apache.jackrabbit.core.id.ItemId;
-import org.apache.jackrabbit.core.util.Dumpable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -43,36 +43,27 @@ import java.util.Map;
  * </ul>
  * This implementation of ItemStateCache is thread-safe.
  */
-public class ItemStateReferenceCache implements ItemStateCache, Dumpable {
+public class ItemStateReferenceCache implements ItemStateCache {
 
     /** Logger instance */
     private static Logger log = LoggerFactory.getLogger(ItemStateReferenceCache.class);
 
     /**
-     * primary cache storing weak references to <code>ItemState</code>
-     * instances.
+     * Cache that automatically flushes entries based on some eviction policy;
+     * entries flushed from the secondary cache will be indirectly flushed
+     * from the reference map by the garbage collector if they thus are
+     * rendered weakly reachable.
      */
-    @SuppressWarnings("unchecked")
-    private final Map<ItemId, ItemState> refs =
-        // I tried using soft instead of weak references here, but that
-        // seems to have some unexpected performance consequences (notable
-        // increase in the JCR TCK run time). So even though soft references
-        // are generally recommended over weak references for caching
-        // purposes, it seems that using weak references is safer here.
-        new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK);
+    private final ItemStateCache cache;
 
     /**
-     * secondary cache that automatically flushes entries based on some
-     * eviction policy; entries flushed from the secondary cache will be
-     * indirectly flushed from the primary (reference) cache by the garbage
-     * collector if they thus are rendered weakly reachable.
+     * Segments of the weak reference map used to keep track of item states.
      */
-    private final ItemStateCache cache;
+    private final Map<ItemId, ItemState>[] segments;
 
     /**
      * Creates a new <code>ItemStateReferenceCache</code> that uses a
-     * <code>MLRUItemStateCache</code> instance as internal secondary
-     * cache.
+     * <code>MLRUItemStateCache</code> instance as internal cache.
      */
     public ItemStateReferenceCache(ItemStateCacheFactory cacheFactory) {
         this(cacheFactory.newItemStateCache());
@@ -85,103 +76,143 @@ public class ItemStateReferenceCache imp
      *
      * @param cache secondary cache implementing a custom eviction policy
      */
+    @SuppressWarnings("unchecked")
     public ItemStateReferenceCache(ItemStateCache cache) {
         this.cache = cache;
+        this.segments = new Map[Runtime.getRuntime().availableProcessors()];
+        for (int i = 0; i < segments.length; i++) {
+            // I tried using soft instead of weak references here, but that
+            // seems to have some unexpected performance consequences (notable
+            // increase in the JCR TCK run time). So even though soft references
+            // are generally recommended over weak references for caching
+            // purposes, it seems that using weak references is safer here.
+            segments[i] =
+                new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK);
+        }
+    }
+
+    /**
+     * Returns the reference map segment for the given entry key. The segment
+     * is selected based on the hash code of the key, after a transformation
+     * to prevent interfering with the optimal performance of the segment
+     * hash map.
+     *
+     * @param id item identifer
+     * @return reference map segment
+     */
+    private Map<ItemId, ItemState> getSegment(ItemId id) {
+        // Unsigned shift right to prevent negative indexes and to
+        // prevent too similar keys to all get stored in the same segment
+        return segments[(id.hashCode() >>> 1) % segments.length];
     }
 
     //-------------------------------------------------------< ItemStateCache >
     /**
      * {@inheritDoc}
      */
-    public synchronized boolean isCached(ItemId id) {
-        // check primary cache
-        return refs.containsKey(id);
+    public boolean isCached(ItemId id) {
+        Map<ItemId, ItemState> segment = getSegment(id);
+        synchronized (segment) {
+            return segment.containsKey(id);
+        }
     }
 
     /**
      * {@inheritDoc}
      */
-    public synchronized ItemState retrieve(ItemId id) {
-        // fake call to update stats of secondary cache
-        cache.retrieve(id);
+    public ItemState retrieve(ItemId id) {
+        // Update the access statistics in the cache
+        ItemState state = cache.retrieve(id);
+        if (state != null) {
+            // Return fast to avoid the second lookup below
+            return state;
+        }
 
-        // retrieve from primary cache
-        return refs.get(id);
+        Map<ItemId, ItemState> segment = getSegment(id);
+        synchronized (segment) {
+            return segment.get(id);
+        }
     }
 
     /**
      * {@inheritDoc}
      */
-    public synchronized ItemState[] retrieveAll() {
-        // values of primary cache
-        return (ItemState[]) refs.values().toArray(new ItemState[refs.size()]);
+    public ItemState[] retrieveAll() {
+        List<ItemState> states = new ArrayList<ItemState>();
+        for (int i = 0; i < segments.length; i++) {
+            synchronized (segments[i]) {
+                states.addAll(segments[i].values());
+            }
+        }
+        return states.toArray(new ItemState[states.size()]);
     }
 
     /**
      * {@inheritDoc}
      */
-    public synchronized void cache(ItemState state) {
-        ItemId id = state.getId();
-        if (refs.containsKey(id)) {
-            log.warn("overwriting cached entry " + id);
-        }
-        // fake call to update stats of secondary cache
+    public void cache(ItemState state) {
+        // Update the cache
         cache.cache(state);
-        // store weak reference in primary cache
-        refs.put(id, state);
 
+        // Store a weak reference in the reference map
+        ItemId id = state.getId();
+        Map<ItemId, ItemState> segment = getSegment(id);
+        synchronized (segment) {
+            if (segment.containsKey(id)) {
+                log.warn("overwriting cached entry " + id);
+            }
+            segment.put(id, state);
+        }
     }
 
     /**
      * {@inheritDoc}
      */
-    public synchronized void evict(ItemId id) {
-        // fake call to update stats of secondary cache
+    public void evict(ItemId id) {
+        // Update the cache
         cache.evict(id);
-        // remove from primary cache
-        refs.remove(id);
+        // Remove from reference map
+        // TODO: Allow the weak reference to be cleared automatically?
+        Map<ItemId, ItemState> segment = getSegment(id);
+        synchronized (segment) {
+            segment.remove(id);
+        }
     }
 
     /**
      * {@inheritDoc}
      */
-    public synchronized void dispose() {
+    public void dispose() {
         cache.dispose();
     }
 
     /**
      * {@inheritDoc}
      */
-    public synchronized void evictAll() {
-        // fake call to update stats of secondary cache
+    public void evictAll() {
+        // Update the cache
         cache.evictAll();
-        // remove all weak references from primary cache
-        refs.clear();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public synchronized void update(ItemId id) {
-        // delegate
-        cache.update(id);
+        // remove all weak references from reference map
+        // TODO: Allow the weak reference to be cleared automatically?
+        for (int i = 0; i < segments.length; i++) {
+            synchronized (segments[i]) {
+                segments[i].clear();
+            }
+        }
     }
 
     /**
      * {@inheritDoc}
      */
-    public synchronized boolean isEmpty() {
-        // check primary cache
-        return refs.isEmpty();
+    public boolean isEmpty() {
+        for (int i = 0; i < segments.length; i++) {
+            synchronized (segments[i]) {
+                if (!segments[i].isEmpty()) {
+                    return false;
+                }
+            }
+        }
+        return true;
     }
 
-    //-------------------------------------------------------------< Dumpable >
-    /**
-     * {@inheritDoc}
-     */
-    public synchronized void dump(PrintStream ps) {
-        ps.println("ItemStateReferenceCache (" + this + ")");
-        ps.println("  refs: " + refs.keySet());
-        ps.println();
-    }
 }

Modified: jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/LocalItemStateManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/LocalItemStateManager.java?rev=1026025&r1=1026024&r2=1026025&view=diff
==============================================================================
--- jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/LocalItemStateManager.java (original)
+++ jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/LocalItemStateManager.java Thu Oct 21 15:13:34 2010
@@ -163,19 +163,17 @@ public class LocalItemStateManager
             return state;
         }
 
-        // check cache. synchronized to ensure an entry is not created twice.
-        synchronized (this) {
-            state = cache.retrieve(id);
-            if (state == null) {
-                // regular behaviour
-                if (id.denotesNode()) {
-                    state = getNodeState((NodeId) id);
-                } else {
-                    state = getPropertyState((PropertyId) id);
-                }
+        // check cache
+        state = cache.retrieve(id);
+        if (state == null) {
+            // regular behaviour
+            if (id.denotesNode()) {
+                state = getNodeState((NodeId) id);
+            } else {
+                state = getPropertyState((PropertyId) id);
             }
-            return state;
         }
+        return state;
     }
 
     /**

Modified: jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/MLRUItemStateCache.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/MLRUItemStateCache.java?rev=1026025&r1=1026024&r2=1026025&view=diff
==============================================================================
--- jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/MLRUItemStateCache.java (original)
+++ jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/MLRUItemStateCache.java Thu Oct 21 15:13:34 2010
@@ -16,14 +16,9 @@
  */
 package org.apache.jackrabbit.core.state;
 
-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.cache.Cache;
-import org.apache.jackrabbit.core.cache.CacheAccessListener;
+import org.apache.jackrabbit.core.cache.CacheManager;
+import org.apache.jackrabbit.core.cache.ConcurrentCache;
 import org.apache.jackrabbit.core.id.ItemId;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -38,139 +33,59 @@ import org.slf4j.LoggerFactory;
  * TODO rename class to something more appropriate, e.g. FIFOItemSateCache since
  * it doesn't use a LRU eviction policy anymore.
  */
-public class MLRUItemStateCache implements ItemStateCache, Cache {
+public class MLRUItemStateCache implements ItemStateCache {
+
     /** Logger instance */
     private static Logger log = LoggerFactory.getLogger(MLRUItemStateCache.class);
 
     /** default maximum memory to use */
     public static final int DEFAULT_MAX_MEM = 4 * 1024 * 1024;
 
-    /** the amount of memory the entries use */
-    private volatile long totalMem;
-
-    /** the maximum of memory the cache may use */
-    private volatile long maxMem;
-
     /** the number of writes */
-    private volatile long numWrites;
-
-    /** the access count */
-    private volatile long accessCount;
+    private volatile long numWrites = 0;
 
-    /** the cache access listeners */
-    private CacheAccessListener accessListener;
-
-    /**
-     * A cache for <code>ItemState</code> instances
-     */
-    private final Map<ItemId, Entry> cache;
-
-    /**
-     * Constructs a new, empty <code>ItemStateCache</code> with a maximum amount
-     * of memory of {@link #DEFAULT_MAX_MEM}.
-     */
-    public MLRUItemStateCache() {
-        this(DEFAULT_MAX_MEM);
-    }
+    private final ConcurrentCache<ItemId, ItemState> cache =
+        new ConcurrentCache<ItemId, ItemState>();
 
-    /**
-     * Constructs a new, empty <code>ItemStateCache</code> with the specified
-     * maximum memory.
-     *
-     * @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) {
-                long maxMem = MLRUItemStateCache.this.maxMem;
-                if (totalMem <= maxMem) {
-                    return false;
-                } else if (totalMem - e.getValue().size <= maxMem) {
-                    totalMem -= e.getValue().size;
-                    return true;
-                } else {
-                    shrink();
-                    return false;
-                }
-            }
-        };
+    public MLRUItemStateCache(CacheManager cacheMgr) {
+        cache.setMaxMemorySize(DEFAULT_MAX_MEM);
+        cache.setAccessListener(cacheMgr);
+        cacheMgr.add(cache);
     }
 
     //-------------------------------------------------------< ItemStateCache >
+
     /**
      * {@inheritDoc}
      */
     public boolean isCached(ItemId id) {
-        synchronized (cache) {
-            return cache.containsKey(id);
-        }
+        return cache.containsKey(id);
     }
 
     /**
      * {@inheritDoc}
      */
     public ItemState retrieve(ItemId id) {
-        touch();
-        synchronized (cache) {
-            Entry entry = cache.get(id);
-            if (entry != null) {
-                return entry.state;
-            } else {
-                return null;
-            }
-        }
+        return cache.get(id);
     }
 
     /**
      * {@inheritDoc}
      */
     public ItemState[] retrieveAll() {
-        synchronized (cache) {
-            ItemState[] states = new ItemState[cache.size()];
-            int i = 0;
-            for (Entry entry : cache.values()) {
-                states[i++] = entry.state;
-            }
-            return states;
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public void update(ItemId id) {
-        touch();
-        synchronized (cache) {
-            Entry entry = cache.get(id);
-            if (entry != null) {
-                totalMem -= entry.size;
-                entry.recalc();
-                totalMem += entry.size;
-            }
-        }
+        return cache.values();
     }
 
     /**
      * {@inheritDoc}
      */
     public void cache(ItemState state) {
-        touch();
-        synchronized (cache) {
-            ItemId id = state.getId();
-            if (cache.containsKey(id)) {
-                log.warn("overwriting cached entry " + id);
-                evict(id);
-            }
-            Entry entry = new Entry(state);
-            totalMem += entry.size;
-            cache.put(id, entry);
-            if (numWrites++ % 10000 == 0 && log.isDebugEnabled()) {
-                log.debug(this + " size=" + cache.size() + ", " + totalMem + "/" + maxMem);
-            }
+        cache.put(state.getId(), state, state.calculateMemoryFootprint());
+
+        if (numWrites++ % 10000 == 0 && log.isDebugEnabled()) {
+            log.debug("Item state cache size: {}% of {} bytes",
+                    cache.getMemoryUsed() * 100 / cache.getMaxMemorySize(),
+                    cache.getMaxMemorySize());
         }
     }
 
@@ -178,135 +93,28 @@ public class MLRUItemStateCache implemen
      * {@inheritDoc}
      */
     public void evict(ItemId id) {
-        touch();
-        synchronized (cache) {
-            Entry entry = cache.remove(id);
-            if (entry != null) {
-                totalMem -= entry.size;
-            }
-        }
+        cache.remove(id);
     }
 
     /**
      * {@inheritDoc}
      */
     public void evictAll() {
-        synchronized (cache) {
-            cache.clear();
-            totalMem = 0;
-        }
+        cache.clear();
     }
 
     /**
      * {@inheritDoc}
      */
     public boolean isEmpty() {
-        synchronized (cache) {
-            return cache.isEmpty();
-        }
-    }
-
-    private void touch() {
-        accessCount++;
-        if ((accessCount % CacheAccessListener.ACCESS_INTERVAL) == 0) {
-            if (accessListener != null) {
-                accessListener.cacheAccessed();
-            }
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public long getAccessCount() {
-        return accessCount;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public long getMaxMemorySize() {
-        return maxMem;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public long getMemoryUsed() {
-        return totalMem;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public void resetAccessCount() {
-        synchronized (cache) {
-            accessCount = 0;
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public void setMaxMemorySize(long size) {
-        synchronized (cache) {
-            this.maxMem = size;
-
-            // remove items, if too many
-            if (totalMem > maxMem) {
-                shrink();
-            }
-        }
-    }
-
-    private void shrink() {
-        List<Map.Entry<ItemId, Entry>> list =
-            new ArrayList<Map.Entry<ItemId, Entry>>(cache.entrySet());
-        for (int i = list.size() - 1; totalMem > maxMem && i >= 0; i--) {
-            Map.Entry<ItemId, Entry> last = list.get(i);
-            totalMem -= last.getValue().size;
-            cache.remove(last.getKey());
-        }
-    }
-
-    /**
-     * Set the cache access listener. Only one listener per cache is supported.
-     *
-     * @param listener the new listener
-     */
-    public void setAccessListener(CacheAccessListener listener) {
-        this.accessListener = listener;
+        return cache.isEmpty();
     }
 
     /**
      * {@inheritDoc}
      */
     public void dispose() {
-        synchronized (cache) {
-            if (accessListener != null) {
-                accessListener.disposeCache(this);
-            }
-        }
-    }
-
-
-    /**
-     * Internal cache entry.
-     */
-    private static class Entry {
-
-        private final ItemState state;
-
-        private long size;
-
-        public Entry(ItemState state) {
-            this.state = state;
-            this.size = 64 + state.calculateMemoryFootprint();
-        }
-
-        public void recalc() {
-            size = 64 + state.calculateMemoryFootprint();
-        }
+        cache.dispose();
     }
 
 }

Modified: jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/ManagedMLRUItemStateCacheFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/ManagedMLRUItemStateCacheFactory.java?rev=1026025&r1=1026024&r2=1026025&view=diff
==============================================================================
--- jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/ManagedMLRUItemStateCacheFactory.java (original)
+++ jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/ManagedMLRUItemStateCacheFactory.java Thu Oct 21 15:13:34 2010
@@ -41,10 +41,7 @@ public class ManagedMLRUItemStateCacheFa
      * Create a new cache instance and link it to the cache manager.
      */
     public ItemStateCache newItemStateCache() {
-        MLRUItemStateCache cache = new MLRUItemStateCache();
-        cacheMgr.add(cache);
-        cache.setAccessListener(cacheMgr);
-        return cache;
+        return new MLRUItemStateCache(cacheMgr);
     }
 
 }

Modified: jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java?rev=1026025&r1=1026024&r2=1026025&view=diff
==============================================================================
--- jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java (original)
+++ jackrabbit/branches/2.0/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java Thu Oct 21 15:13:34 2010
@@ -1708,21 +1708,8 @@ public class SharedItemStateManager
             // not found in cache, load from persistent storage
             state = loadItemState(id);
             state.setStatus(ItemState.STATUS_EXISTING);
-            synchronized (this) {
-                // Use a double check to ensure that the cache entry is
-                // not created twice. We don't synchronize the entire
-                // method to allow the first cache retrieval to proceed
-                // even when another thread is loading a new item state.
-                ItemState cachedState = cache.retrieve(id);
-                if (cachedState == null) {
-                    // put it in cache
-                    cache.cache(state);
-                    // set parent container
-                    state.setContainer(this);
-                } else {
-                    state = cachedState;
-                }
-            }
+            state.setContainer(this);
+            cache.cache(state);
         }
         return state;
     }