You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by an...@apache.org on 2008/02/07 15:01:21 UTC

svn commit: r619416 - in /jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi: ItemCache.java ItemCacheImpl.java ItemManager.java ItemManagerImpl.java SessionImpl.java

Author: angela
Date: Thu Feb  7 06:01:18 2008
New Revision: 619416

URL: http://svn.apache.org/viewvc?rev=619416&view=rev
Log:
JCR-1011: JCR2SPI: add configurable cache for Item instances (ItemManager)

Added:
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemCache.java   (with props)
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemCacheImpl.java   (with props)
Modified:
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemManager.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemManagerImpl.java
    jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/SessionImpl.java

Added: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemCache.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemCache.java?rev=619416&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemCache.java (added)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemCache.java Thu Feb  7 06:01:18 2008
@@ -0,0 +1,43 @@
+/*
+ * 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.jackrabbit.jcr2spi;
+
+import org.apache.jackrabbit.jcr2spi.state.ItemState;
+
+import javax.jcr.Item;
+
+/**
+ * <code>ItemCache</code>...
+ */
+public interface ItemCache extends ItemLifeCycleListener {
+
+    /**
+     * Returns the cached <code>Item</code> that belongs to the given
+     * <code>ItemState</code> or <code>null</code> if the cache does not
+     * contain that <code>Item</code>.
+     *
+     * @param state State of the item that should be retrieved.
+     * @return The item reference stored in the corresponding cache entry
+     * or <code>null</code> if there's no corresponding cache entry.
+     */
+    Item getItem(ItemState state);
+
+    /**
+     * Clear all entries in the ItemCache and free resources.
+     */
+    void clear();
+}
\ No newline at end of file

Propchange: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemCache.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemCache.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemCacheImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemCacheImpl.java?rev=619416&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemCacheImpl.java (added)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemCacheImpl.java Thu Feb  7 06:01:18 2008
@@ -0,0 +1,166 @@
+/*
+ * 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.jackrabbit.jcr2spi;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.jackrabbit.jcr2spi.state.ItemState;
+import org.apache.jackrabbit.jcr2spi.util.Dumpable;
+import org.apache.commons.collections.map.LRUMap;
+
+import javax.jcr.Item;
+import javax.jcr.RepositoryException;
+import java.util.Map;
+import java.util.Iterator;
+import java.io.PrintStream;
+
+/**
+ * <code>ItemCacheImpl</code>...
+ */
+public class ItemCacheImpl implements ItemCache, Dumpable {
+
+    private static Logger log = LoggerFactory.getLogger(ItemCacheImpl.class);
+
+    private final Map cache;
+
+    ItemCacheImpl(int maxSize) {
+        cache = new LRUMap(maxSize);
+    }
+
+    //----------------------------------------------------------< ItemCache >---
+    /**
+     * @see ItemCache#getItem(ItemState)
+     */
+    public Item getItem(ItemState state) {
+        return (Item) cache.get(state);
+    }
+
+    /**
+     * @see ItemCache#clear()
+     */
+    public void clear() {
+        cache.clear();
+    }
+
+    //----------------------------------------------< ItemLifeCycleListener >---
+    /**
+     * @see ItemLifeCycleListener#itemCreated(Item)
+     */
+    public void itemCreated(Item item) {
+        if (!(item instanceof ItemImpl)) {
+            String msg = "Incompatible Item object: " + ItemImpl.class.getName() + " expected.";
+            throw new IllegalArgumentException(msg);
+        }
+        if (log.isDebugEnabled()) {
+            log.debug("created item " + item);
+        }
+        // add instance to cache
+        cacheItem(((ItemImpl)item).getItemState(), item);
+    }
+
+    /**
+     * @see ItemLifeCycleListener#itemInvalidated(Item)
+     */
+    public void itemInvalidated(Item item) {
+        if (!(item instanceof ItemImpl)) {
+            String msg = "Incompatible Item object: " + ItemImpl.class.getName() + " expected.";
+            throw new IllegalArgumentException(msg);
+        }
+        if (log.isDebugEnabled()) {
+            log.debug("invalidated item " + item);
+        }
+        // remove instance from cache
+        evictItem(((ItemImpl)item).getItemState());
+    }
+
+    /**
+     * @see ItemLifeCycleListener#itemDestroyed(Item)
+     */
+    public void itemDestroyed(Item item) {
+        if (!(item instanceof ItemImpl)) {
+            String msg = "Incompatible Item object: " + ItemImpl.class.getName() + " expected.";
+            throw new IllegalArgumentException(msg);
+        }
+        if (log.isDebugEnabled()) {
+            log.debug("destroyed item " + item);
+        }
+        // we're no longer interested in this item
+        ((ItemImpl)item).removeLifeCycleListener(this);
+        // remove instance from cache
+        evictItem(((ItemImpl)item).getItemState());
+    }
+
+    //-------------------------------------------------< item cache methods >---
+    /**
+     * Puts the reference of an item in the cache with
+     * the item's path as the key.
+     *
+     * @param item the item to cache
+     */
+    private synchronized void cacheItem(ItemState state, Item item) {
+        if (cache.containsKey(state)) {
+            log.warn("overwriting cached item " + state);
+        }
+        if (log.isDebugEnabled()) {
+            log.debug("caching item " + state);
+        }
+        cache.put(state, item);
+    }
+
+    /**
+     * Removes a cache entry for a specific item.
+     *
+     * @param itemState state of the item to remove from the cache
+     */
+    private synchronized void evictItem(ItemState itemState) {
+        if (log.isDebugEnabled()) {
+            log.debug("removing item " + itemState + " from cache");
+        }
+        cache.remove(itemState);
+    }
+
+    //-----------------------------------------------------------< Dumpable >---
+    /**
+     * @see Dumpable#dump(PrintStream)
+     */
+    public void dump(PrintStream ps) {
+        Iterator iter = cache.keySet().iterator();
+        while (iter.hasNext()) {
+            ItemState state = (ItemState) iter.next();
+            Item item = (Item) cache.get(state);
+            if (item.isNode()) {
+                ps.print("Node: ");
+            } else {
+                ps.print("Property: ");
+            }
+            if (item.isNew()) {
+                ps.print("new ");
+            } else if (item.isModified()) {
+                ps.print("modified ");
+            } else {
+                ps.print("- ");
+            }
+            String path;
+            try {
+                path = item.getPath();
+            } catch (RepositoryException e) {
+                path = "-";
+            }
+            ps.println(state + "\t" + path + " (" + item + ")");
+        }
+    }
+}
\ No newline at end of file

Propchange: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemCacheImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemCacheImpl.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemManager.java?rev=619416&r1=619415&r2=619416&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemManager.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemManager.java Thu Feb  7 06:01:18 2008
@@ -50,7 +50,7 @@
  * If the parent <code>Session</code> is an <code>XASession</code>, there is
  * one <code>ItemManager</code> instance per started global transaction.
  */
-public interface ItemManager extends ItemLifeCycleListener {
+public interface ItemManager {
 
     /**
      * Disposes this <code>ItemManager</code> and frees resources.

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemManagerImpl.java?rev=619416&r1=619415&r2=619416&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemManagerImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemManagerImpl.java Thu Feb  7 06:01:18 2008
@@ -23,6 +23,7 @@
 import org.apache.jackrabbit.jcr2spi.state.ItemState;
 import org.apache.jackrabbit.jcr2spi.state.NodeState;
 import org.apache.jackrabbit.jcr2spi.state.PropertyState;
+import org.apache.jackrabbit.jcr2spi.state.ItemStateCreationListener;
 import org.apache.jackrabbit.jcr2spi.util.Dumpable;
 import org.apache.jackrabbit.jcr2spi.util.LogUtil;
 import org.apache.jackrabbit.jcr2spi.version.VersionHistoryImpl;
@@ -30,7 +31,6 @@
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.Path;
 import org.apache.jackrabbit.spi.commons.name.NameConstants;
-import org.apache.commons.collections.map.ReferenceMap;
 import org.slf4j.LoggerFactory;
 import org.slf4j.Logger;
 
@@ -41,14 +41,14 @@
 import javax.jcr.PropertyIterator;
 import javax.jcr.RepositoryException;
 import javax.jcr.Item;
+import javax.jcr.Workspace;
 import java.io.PrintStream;
 import java.util.Iterator;
-import java.util.Map;
 
 /**
  * <code>ItemManagerImpl</code> implements the <code>ItemManager</code> interface.
  */
-public class ItemManagerImpl implements Dumpable, ItemManager {
+public class ItemManagerImpl implements Dumpable, ItemManager, ItemStateCreationListener {
 
     private static Logger log = LoggerFactory.getLogger(ItemManagerImpl.class);
 
@@ -63,19 +63,26 @@
      * o.a.j.core the item state are copied to transient space for reading and
      * will therefor not change upon transient modifications.
      */
-    private Map itemCache;
+    private final ItemCache itemCache;
 
     /**
      * Creates a new per-session instance <code>ItemManagerImpl</code> instance.
      *
      * @param hierMgr HierarchyManager associated with the new instance
      * @param session the session associated with the new instance
+     * @param cache the ItemCache to be used.
      */
-    ItemManagerImpl(HierarchyManager hierMgr, SessionImpl session) {
+    ItemManagerImpl(HierarchyManager hierMgr, SessionImpl session, ItemCache cache) {
         this.hierMgr = hierMgr;
         this.session = session;
-        /* Setup item cache with weak keys (ItemState) and weak values (Item).*/
-        itemCache = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK);
+        itemCache = cache;
+
+        // start listening to creation of ItemStates upon batch-reading in the
+        // workspace item state factory.
+        Workspace wsp = session.getWorkspace();
+        if (wsp instanceof WorkspaceImpl) {
+            ((WorkspaceImpl) wsp).getItemStateFactory().addCreationListener(this);
+        }
     }
 
     //--------------------------------------------------------< ItemManager >---
@@ -83,6 +90,12 @@
      * @see ItemManager#dispose()
      */
     public void dispose() {
+        // stop listening
+        Workspace wsp = session.getWorkspace();
+        if (wsp instanceof WorkspaceImpl) {
+            ((WorkspaceImpl) wsp).getItemStateFactory().removeCreationListener(this);
+        }
+        // aftwards clear the cache.
         itemCache.clear();
     }
 
@@ -173,7 +186,7 @@
         }
 
         // first try to access item from cache
-        Item item = retrieveItem(itemState);
+        Item item = itemCache.getItem(itemState);
         // not yet in cache, need to create instance
         if (item == null) {
             // create instance of item
@@ -256,54 +269,6 @@
         return new LazyItemIterator(this, propEntries);
     }
 
-    //----------------------------------------------< ItemLifeCycleListener >---
-    /**
-     * @see ItemLifeCycleListener#itemCreated(Item)
-     */
-    public void itemCreated(Item item) {
-        if (!(item instanceof ItemImpl)) {
-            String msg = "Incompatible Item object: " + ItemImpl.class.getName() + " expected.";
-            throw new IllegalArgumentException(msg);
-        }
-        if (log.isDebugEnabled()) {
-            log.debug("created item " + item);
-        }
-        // add instance to cache
-        cacheItem(((ItemImpl)item).getItemState(), item);
-    }
-
-    /**
-     * @see ItemLifeCycleListener#itemInvalidated(Item)
-     */
-    public void itemInvalidated(Item item) {
-        if (!(item instanceof ItemImpl)) {
-            String msg = "Incompatible Item object: " + ItemImpl.class.getName() + " expected.";
-            throw new IllegalArgumentException(msg);
-        }
-        if (log.isDebugEnabled()) {
-            log.debug("invalidated item " + item);
-        }
-        // remove instance from cache
-        evictItem(((ItemImpl)item).getItemState());
-    }
-
-    /**
-     * @see ItemLifeCycleListener#itemDestroyed(Item)
-     */
-    public void itemDestroyed(Item item) {
-        if (!(item instanceof ItemImpl)) {
-            String msg = "Incompatible Item object: " + ItemImpl.class.getName() + " expected.";
-            throw new IllegalArgumentException(msg);
-        }
-        if (log.isDebugEnabled()) {
-            log.debug("destroyed item " + item);
-        }
-        // we're no longer interested in this item
-        ((ItemImpl)item).removeLifeCycleListener(this);
-        // remove instance from cache
-        evictItem(((ItemImpl)item).getItemState());
-    }
-
     //-----------------------------------------------------------< Dumpable >---
     /**
      * @see Dumpable#dump(PrintStream)
@@ -313,23 +278,10 @@
         ps.println();
         ps.println("Items in cache:");
         ps.println();
-        Iterator iter = itemCache.keySet().iterator();
-        while (iter.hasNext()) {
-            ItemState state = (ItemState) iter.next();
-            Item item = (Item) itemCache.get(state);
-            if (item.isNode()) {
-                ps.print("Node: ");
-            } else {
-                ps.print("Property: ");
-            }
-            if (item.isNew()) {
-                ps.print("new ");
-            } else if (item.isModified()) {
-                ps.print("modified ");
-            } else {
-                ps.print("- ");
-            }
-            ps.println(state + "\t" + LogUtil.safeGetJCRPath(state, session.getPathResolver()) + " (" + item + ")");
+        if (itemCache instanceof Dumpable) {
+            ((Dumpable) itemCache).dump(ps);
+        } else {
+            ps.println("ItemCache (" + itemCache.toString() + ")");
         }
     }
 
@@ -342,7 +294,7 @@
     private NodeImpl createNodeInstance(NodeState state) throws RepositoryException {
         // we want to be informed on life cycle changes of the new node object
         // in order to maintain item cache consistency
-        ItemLifeCycleListener[] listeners = new ItemLifeCycleListener[]{this};
+        ItemLifeCycleListener[] listeners = new ItemLifeCycleListener[]{itemCache};
 
         // check special nodes
         Name ntName = state.getNodeTypeName();
@@ -365,49 +317,32 @@
     private PropertyImpl createPropertyInstance(PropertyState state) {
         // we want to be informed on life cycle changes of the new property object
         // in order to maintain item cache consistency
-        ItemLifeCycleListener[] listeners = new ItemLifeCycleListener[]{this};
+        ItemLifeCycleListener[] listeners = new ItemLifeCycleListener[]{itemCache};
         // create property object
         PropertyImpl prop = new PropertyImpl(this, session, state, listeners);
         return prop;
     }
 
-    //-------------------------------------------------< item cache methods >---
+    //------------------------------------------< ItemStateCreationListener >---
     /**
-     * Puts the reference of an item in the cache with
-     * the item's path as the key.
      *
-     * @param item the item to cache
+     * @param state
      */
-    private void cacheItem(ItemState state, Item item) {
-        if (itemCache.containsKey(state)) {
-            log.warn("overwriting cached item " + state);
-        }
-        if (log.isDebugEnabled()) {
-            log.debug("caching item " + state);
+    public void created(ItemState state) {
+        if (state.isNode()) {
+            try {
+                createNodeInstance((NodeState) state);
+            } catch (RepositoryException e) {
+                // log warning and ignore
+                log.warn("Unable to create Node instance: " + e.getMessage());
+            }
+        } else {
+            createPropertyInstance((PropertyState) state);
         }
-        itemCache.put(state, item);
-    }
-
-    /**
-     * Returns an item reference from the cache.
-     *
-     * @param state State of the item that should be retrieved.
-     * @return the item reference stored in the corresponding cache entry
-     *         or <code>null</code> if there's no corresponding cache entry.
-     */
-    private Item retrieveItem(ItemState state) {
-        return (Item) itemCache.get(state);
     }
 
-    /**
-     * Removes a cache entry for a specific item.
-     *
-     * @param itemState state of the item to remove from the cache
-     */
-    private void evictItem(ItemState itemState) {
-        if (log.isDebugEnabled()) {
-            log.debug("removing item " + itemState + " from cache");
-        }
-        itemCache.remove(itemState);
+    public void statusChanged(ItemState state, int previousStatus) {
+        // nothing to do -> Item is listening to status changes and forces
+        // cleanup of cache entries through it's own status changes.
     }
 }

Modified: jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/SessionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/SessionImpl.java?rev=619416&r1=619415&r2=619416&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/SessionImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/SessionImpl.java Thu Feb  7 06:01:18 2008
@@ -641,7 +641,9 @@
     }
 
     protected ItemManager createItemManager(HierarchyManager hierarchyManager) {
-        return new ItemManagerImpl(hierarchyManager, this);
+        ItemCache cache = new ItemCacheImpl(1000); // TODO: make configurable
+        ItemManagerImpl imgr = new ItemManagerImpl(hierarchyManager, this, cache);
+        return imgr;
     }
 
     //---------------------------------------------------< ManagerProvider > ---