You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by mr...@apache.org on 2005/07/07 16:53:56 UTC

svn commit: r209608 - /incubator/jackrabbit/trunk/core/src/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java

Author: mreutegg
Date: Thu Jul  7 07:53:55 2005
New Revision: 209608

URL: http://svn.apache.org/viewcvs?rev=209608&view=rev
Log:
JCR-164: SharedItemStateManager not properly synchronized
- applying patch as proposed

Modified:
    incubator/jackrabbit/trunk/core/src/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java

Modified: incubator/jackrabbit/trunk/core/src/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/core/src/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java?rev=209608&r1=209607&r2=209608&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/core/src/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java (original)
+++ incubator/jackrabbit/trunk/core/src/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java Thu Jul  7 07:53:55 2005
@@ -38,6 +38,9 @@
 import java.util.ArrayList;
 import java.util.Iterator;
 
+import EDU.oswego.cs.dl.util.concurrent.ReadWriteLock;
+import EDU.oswego.cs.dl.util.concurrent.ReentrantWriterPreferenceReadWriteLock;
+
 /**
  * Shared <code>ItemStateManager</code>. Caches objects returned from a
  * <code>PersistenceManager</code>. Objects returned by this item state
@@ -67,6 +70,11 @@
     private VirtualItemStateProvider[] virtualProviders = new VirtualItemStateProvider[0];
 
     /**
+     * Read-/Write-Lock to synchronize access on this item state manager.
+     */
+    private final ReadWriteLock rwLock = new ReentrantWriterPreferenceReadWriteLock();
+
+    /**
      * Creates a new <code>SharedItemStateManager</code> instance.
      *
      * @param persistMgr
@@ -226,21 +234,28 @@
      */
     public ItemState getItemState(ItemId id)
             throws NoSuchItemStateException, ItemStateException {
-        // check the virtual root ids (needed for overlay)
-        for (int i = 0; i < virtualProviders.length; i++) {
-            if (virtualProviders[i].isVirtualRoot(id)) {
-                return virtualProviders[i].getItemState(id);
+
+        acquireReadLock();
+
+        try {
+            // check the virtual root ids (needed for overlay)
+            for (int i = 0; i < virtualProviders.length; i++) {
+                if (virtualProviders[i].isVirtualRoot(id)) {
+                    return virtualProviders[i].getItemState(id);
+                }
             }
-        }
-        // check internal first
-        if (hasNonVirtualItemState(id)) {
-            return getNonVirtualItemState(id);
-        }
-        // check if there is a virtual state for the specified item
-        for (int i = 0; i < virtualProviders.length; i++) {
-            if (virtualProviders[i].hasItemState(id)) {
-                return virtualProviders[i].getItemState(id);
+            // check internal first
+            if (hasNonVirtualItemState(id)) {
+                return getNonVirtualItemState(id);
             }
+            // check if there is a virtual state for the specified item
+            for (int i = 0; i < virtualProviders.length; i++) {
+                if (virtualProviders[i].hasItemState(id)) {
+                    return virtualProviders[i].getItemState(id);
+                }
+            }
+        } finally {
+            rwLock.readLock().release();
         }
         throw new NoSuchItemStateException(id.toString());
     }
@@ -271,24 +286,36 @@
      * {@inheritDoc}
      */
     public boolean hasItemState(ItemId id) {
-        if (isCached(id)) {
-            return true;
+
+        try {
+            acquireReadLock();
+        } catch (ItemStateException e) {
+            return false;
         }
-        // check the virtual root ids (needed for overlay)
-        for (int i = 0; i < virtualProviders.length; i++) {
-            if (virtualProviders[i].isVirtualRoot(id)) {
+
+        try {
+            if (isCached(id)) {
                 return true;
             }
-        }
-        // check if this manager has the item state
-        if (hasNonVirtualItemState(id)) {
-            return true;
-        }
-        // otherwise check virtual ones
-        for (int i = 0; i < virtualProviders.length; i++) {
-            if (virtualProviders[i].hasItemState(id)) {
+
+            // check the virtual root ids (needed for overlay)
+            for (int i = 0; i < virtualProviders.length; i++) {
+                if (virtualProviders[i].isVirtualRoot(id)) {
+                    return true;
+                }
+            }
+            // check if this manager has the item state
+            if (hasNonVirtualItemState(id)) {
                 return true;
             }
+            // otherwise check virtual ones
+            for (int i = 0; i < virtualProviders.length; i++) {
+                if (virtualProviders[i].hasItemState(id)) {
+                    return true;
+                }
+            }
+        } finally {
+            rwLock.readLock().release();
         }
         return false;
     }
@@ -319,19 +346,25 @@
     public NodeReferences getNodeReferences(NodeReferencesId id)
             throws NoSuchItemStateException, ItemStateException {
 
-        // check persistence manager
+        acquireReadLock();
+
         try {
-            return persistMgr.load(id);
-        } catch (NoSuchItemStateException e) {
-            // ignore
-        }
-        // check virtual providers
-        for (int i = 0; i < virtualProviders.length; i++) {
+            // check persistence manager
             try {
-                return virtualProviders[i].getNodeReferences(id);
+                return persistMgr.load(id);
             } catch (NoSuchItemStateException e) {
                 // ignore
             }
+            // check virtual providers
+            for (int i = 0; i < virtualProviders.length; i++) {
+                try {
+                    return virtualProviders[i].getNodeReferences(id);
+                } catch (NoSuchItemStateException e) {
+                    // ignore
+                }
+            }
+        } finally {
+            rwLock.readLock().release();
         }
 
         // throw
@@ -343,19 +376,29 @@
      */
     public boolean hasNodeReferences(NodeReferencesId id) {
 
-        // check persistence manager
         try {
-            if (persistMgr.exists(id)) {
-                return true;
-            }
+            acquireReadLock();
         } catch (ItemStateException e) {
-            // ignore
+            return false;
         }
-        // check virtual providers
-        for (int i = 0; i < virtualProviders.length; i++) {
-            if (virtualProviders[i].hasNodeReferences(id)) {
-                return true;
+
+        try {
+            // check persistence manager
+            try {
+                if (persistMgr.exists(id)) {
+                    return true;
+                }
+            } catch (ItemStateException e) {
+                // ignore
+            }
+            // check virtual providers
+            for (int i = 0; i < virtualProviders.length; i++) {
+                if (virtualProviders[i].hasNodeReferences(id)) {
+                    return true;
+                }
             }
+        } finally {
+            rwLock.readLock().release();
         }
         return false;
     }
@@ -482,136 +525,166 @@
         // todo: remember by provider
         ArrayList virtualRefs = new ArrayList();
 
-        /**
-         * Validate modified references. Target node of references may
-         * have been deleted in the meantime.
-         */
-        Iterator iter = local.modifiedRefs();
-        while (iter.hasNext()) {
-            NodeReferences refs = (NodeReferences) iter.next();
-            NodeId id = new NodeId(refs.getUUID());
-            // if targetid is in virtual provider, transfer to its modified set
-            for (int i = 0; i < virtualProviders.length; i++) {
-                VirtualItemStateProvider provider = virtualProviders[i];
-                if (provider.hasItemState(id)) {
-                    virtualRefs.add(refs);
-                    refs = null;
-                    break;
-                }
-            }
-            if (refs != null) {
-                if (refs.hasReferences()) {
-                    if (!local.has(id) && !hasItemState(id)) {
-                        String msg = "Target node " + id
-                                + " of REFERENCE property does not exist";
-                        throw new ItemStateException(msg);
-                    }
-                }
-                shared.modified(refs);
-            }
-        }
-
-        EventStateCollection events = null;
-        boolean succeeded = false;
+        acquireWriteLock();
 
         try {
             /**
-             * Reconnect all items contained in the change log to their
-             * respective shared item and add the shared items to a
-             * new change log.
+             * Validate modified references. Target node of references may
+             * have been deleted in the meantime.
              */
-            iter = local.modifiedStates();
-            while (iter.hasNext()) {
-                ItemState state = (ItemState) iter.next();
-                state.connect(getItemState(state.getId()));
-                shared.modified(state.getOverlayedState());
-            }
-            iter = local.deletedStates();
+            Iterator iter = local.modifiedRefs();
             while (iter.hasNext()) {
-                ItemState state = (ItemState) iter.next();
-                state.connect(getItemState(state.getId()));
-                shared.deleted(state.getOverlayedState());
-            }
-            iter = local.addedStates();
-            while (iter.hasNext()) {
-                ItemState state = (ItemState) iter.next();
-                state.connect(createInstance(state));
-                shared.added(state.getOverlayedState());
-            }
-
-            /* prepare the events */
-            if (obsMgr != null) {
-                events = obsMgr.createEventStateCollection();
-                events.createEventStates(root.getUUID(), local, this);
-                events.prepare();
-            }
-
-            /* Push all changes from the local items to the shared items */
-            local.push();
-
-            /* Store items in the underlying persistence manager */
-            long t0 = System.currentTimeMillis();
-            persistMgr.store(shared);
-            succeeded = true;
-            long t1 = System.currentTimeMillis();
-            if (log.isInfoEnabled()) {
-                log.info("persisting change log " + shared + " took " + (t1 - t0) + "ms");
+                NodeReferences refs = (NodeReferences) iter.next();
+                NodeId id = new NodeId(refs.getUUID());
+                // if targetid is in virtual provider, transfer to its modified set
+                for (int i = 0; i < virtualProviders.length; i++) {
+                    VirtualItemStateProvider provider = virtualProviders[i];
+                    if (provider.hasItemState(id)) {
+                        virtualRefs.add(refs);
+                        refs = null;
+                        break;
+                    }
+                }
+                if (refs != null) {
+                    if (refs.hasReferences()) {
+                        if (!local.has(id) && !hasItemState(id)) {
+                            String msg = "Target node " + id
+                                    + " of REFERENCE property does not exist";
+                            throw new ItemStateException(msg);
+                        }
+                    }
+                    shared.modified(refs);
+                }
             }
 
-        } finally {
+            EventStateCollection events = null;
+            boolean succeeded = false;
 
-            /**
-             * If some store operation was unsuccessful, we have to reload
-             * the state of modified and deleted items from persistent
-             * storage.
-             */
-            if (!succeeded) {
-                local.disconnect();
-
-                iter = shared.modifiedStates();
+            try {
+                /**
+                 * Reconnect all items contained in the change log to their
+                 * respective shared item and add the shared items to a
+                 * new change log.
+                 */
+                iter = local.modifiedStates();
                 while (iter.hasNext()) {
                     ItemState state = (ItemState) iter.next();
-                    try {
-                        state.copy(loadItemState(state.getId()));
-                    } catch (ItemStateException e) {
-                        state.discard();
-                    }
+                    state.connect(getItemState(state.getId()));
+                    shared.modified(state.getOverlayedState());
                 }
-                iter = shared.deletedStates();
+                iter = local.deletedStates();
                 while (iter.hasNext()) {
                     ItemState state = (ItemState) iter.next();
-                    try {
-                        state.copy(loadItemState(state.getId()));
-                    } catch (ItemStateException e) {
-                        state.discard();
-                    }
+                    state.connect(getItemState(state.getId()));
+                    shared.deleted(state.getOverlayedState());
                 }
-                iter = shared.addedStates();
+                iter = local.addedStates();
                 while (iter.hasNext()) {
                     ItemState state = (ItemState) iter.next();
-                    state.discard();
+                    state.connect(createInstance(state));
+                    shared.added(state.getOverlayedState());
+                }
+
+                /* prepare the events */
+                if (obsMgr != null) {
+                    events = obsMgr.createEventStateCollection();
+                    events.createEventStates(root.getUUID(), local, this);
+                    events.prepare();
+                }
+
+                /* Push all changes from the local items to the shared items */
+                local.push();
+
+                /* Store items in the underlying persistence manager */
+                long t0 = System.currentTimeMillis();
+                persistMgr.store(shared);
+                succeeded = true;
+                long t1 = System.currentTimeMillis();
+                if (log.isInfoEnabled()) {
+                    log.info("persisting change log " + shared + " took " + (t1 - t0) + "ms");
+                }
+
+            } finally {
+
+                /**
+                 * If some store operation was unsuccessful, we have to reload
+                 * the state of modified and deleted items from persistent
+                 * storage.
+                 */
+                if (!succeeded) {
+                    local.disconnect();
+
+                    iter = shared.modifiedStates();
+                    while (iter.hasNext()) {
+                        ItemState state = (ItemState) iter.next();
+                        try {
+                            state.copy(loadItemState(state.getId()));
+                        } catch (ItemStateException e) {
+                            state.discard();
+                        }
+                    }
+                    iter = shared.deletedStates();
+                    while (iter.hasNext()) {
+                        ItemState state = (ItemState) iter.next();
+                        try {
+                            state.copy(loadItemState(state.getId()));
+                        } catch (ItemStateException e) {
+                            state.discard();
+                        }
+                    }
+                    iter = shared.addedStates();
+                    while (iter.hasNext()) {
+                        ItemState state = (ItemState) iter.next();
+                        state.discard();
+                    }
                 }
             }
-        }
 
-        /* Let the shared item listeners know about the change */
-        shared.persisted();
+            /* Let the shared item listeners know about the change */
+            shared.persisted();
 
-        /* notify virtual providers about node references */
-        iter = virtualRefs.iterator();
-        while (iter.hasNext()) {
-            NodeReferences refs = (NodeReferences) iter.next();
-            // if targetid is in virtual provider, transfer to its modified set
-            for (int i = 0; i < virtualProviders.length; i++) {
-                if (virtualProviders[i].setNodeReferences(refs)) {
-                    break;
+            /* notify virtual providers about node references */
+            iter = virtualRefs.iterator();
+            while (iter.hasNext()) {
+                NodeReferences refs = (NodeReferences) iter.next();
+                // if targetid is in virtual provider, transfer to its modified set
+                for (int i = 0; i < virtualProviders.length; i++) {
+                    if (virtualProviders[i].setNodeReferences(refs)) {
+                        break;
+                    }
                 }
             }
+
+            /* dispatch the events */
+            if (events != null) {
+                events.dispatch();
+            }
+        } finally {
+            rwLock.writeLock().release();
+        }
+    }
+
+    /**
+     * Acquires the read lock on this item state manager.
+     * @throws ItemStateException if the read lock cannot be acquired.
+     */
+    private void acquireReadLock() throws ItemStateException {
+        try {
+            rwLock.readLock().acquire();
+        } catch (InterruptedException e) {
+            throw new ItemStateException("Interrupted while acquiring read lock");
         }
+    }
 
-        /* dispatch the events */
-        if (events != null) {
-            events.dispatch();
+    /**
+     * Acquires the write lock on this item state manager.
+     * @throws ItemStateException if the write lock cannot be acquired.
+     */
+    private void acquireWriteLock() throws ItemStateException {
+        try {
+            rwLock.writeLock().acquire();
+        } catch (InterruptedException e) {
+            throw new ItemStateException("Interrupted while acquiring write lock");
         }
     }