You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ck...@apache.org on 2009/09/28 12:30:36 UTC

svn commit: r819491 - in /jackrabbit/trunk/jackrabbit-core/src: main/java/org/apache/jackrabbit/core/state/DefaultISMLocking.java test/java/org/apache/jackrabbit/core/UserTransactionImpl.java test/java/org/apache/jackrabbit/core/XATest.java

Author: ckoell
Date: Mon Sep 28 10:30:36 2009
New Revision: 819491

URL: http://svn.apache.org/viewvc?rev=819491&view=rev
Log:
JCR-769 Unable to login with two different Credentials to same workspace in one Transaction

Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/DefaultISMLocking.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/UserTransactionImpl.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/XATest.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/DefaultISMLocking.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/DefaultISMLocking.java?rev=819491&r1=819490&r2=819491&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/DefaultISMLocking.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/DefaultISMLocking.java Mon Sep 28 10:30:36 2009
@@ -16,10 +16,14 @@
  */
 package org.apache.jackrabbit.core.state;
 
+import java.util.Arrays;
+
 import javax.transaction.xa.Xid;
 
 import org.apache.jackrabbit.core.id.ItemId;
 import org.apache.jackrabbit.core.TransactionContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import EDU.oswego.cs.dl.util.concurrent.ReentrantWriterPreferenceReadWriteLock;
 import EDU.oswego.cs.dl.util.concurrent.Sync;
@@ -32,6 +36,11 @@
 public class DefaultISMLocking implements ISMLocking {
 
     /**
+     * Logger instance
+     */
+    private static final Logger log = LoggerFactory.getLogger(DefaultISMLocking.class);
+
+    /**
      * The internal read-write lock.
      */
     private final RWLock rwLock = new RWLock();
@@ -60,7 +69,6 @@
              * {@inheritDoc}
              */
             public void release() {
-                rwLock.setActiveXid(null);
                 rwLock.writeLock().release();
             }
 
@@ -109,8 +117,36 @@
          * @param xid
          */
         synchronized void setActiveXid(Xid xid) {
+            if (activeXid != null && xid != null) {
+                boolean sameGTI = Arrays.equals(activeXid.getGlobalTransactionId(), xid.getGlobalTransactionId());
+                if (!sameGTI) {
+                    log.warn("Unable to set the ActiveXid while a other one is associated with a different GloalTransactionId with this RWLock.");
+                    return;
+                }
+            }
             activeXid = xid;
         }
-        
+
+        /**
+         * {@inheritDoc}
+         * 
+         * If there are no more writeHolds the activeXid will be set to null
+         */
+        protected synchronized Signaller endWrite() {
+            --writeHolds_;
+            if (writeHolds_ > 0) {  // still being held
+                return null;
+            } else {
+                activeXid = null;
+                activeWriter_ = null;
+                if (waitingReaders_ > 0 && allowReader()) {
+                    return readerLock_;
+                } else if (waitingWriters_ > 0) {
+                    return writerLock_;
+                } else {
+                    return null;
+                }
+            }
+        }
     }
 }

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/UserTransactionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/UserTransactionImpl.java?rev=819491&r1=819490&r2=819491&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/UserTransactionImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/UserTransactionImpl.java Mon Sep 28 10:30:36 2009
@@ -16,6 +16,10 @@
  */
 package org.apache.jackrabbit.core;
 
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
 import javax.transaction.xa.XAResource;
 import javax.transaction.xa.Xid;
 import javax.transaction.xa.XAException;
@@ -41,14 +45,9 @@
     private static byte counter = 0;
 
     /**
-     * XAResource
-     */
-    private final XAResource xares;
-
-    /**
-     * Xid
+     * The XAResources map
      */
-    private Xid xid;
+    private Map xaResources = new HashMap();
 
     /**
      * Status
@@ -75,7 +74,8 @@
      */
     public UserTransactionImpl(Session session, boolean distributedThreadAccess) {
         if (session instanceof XASession) {
-            xares = ((XASession) session).getXAResource();
+            counter++;
+            xaResources.put(((XASession) session).getXAResource(), new XidImpl(counter));
             this.distributedThreadAccess = distributedThreadAccess; 
         } else {
             throw new IllegalArgumentException("Session not of type XASession");
@@ -83,6 +83,14 @@
     }
 
     /**
+     * Enlists the given Session to this UserTransaction
+     * @param session
+     */
+    public void enlistXAResource(Session session) {
+        xaResources.put(session, new XidImpl(counter));
+    }
+
+    /**
      * @see javax.transaction.UserTransaction#begin
      */
     public void begin() throws NotSupportedException, SystemException {
@@ -91,8 +99,11 @@
         }
 
         try {
-            xid = new XidImpl(counter++);
-            xares.start(xid, XAResource.TMNOFLAGS);
+            for (Iterator it = xaResources.keySet().iterator(); it.hasNext(); ) {
+                XAResource resource = (XAResource) it.next();
+                XidImpl xid = (XidImpl) xaResources.get(resource);
+                resource.start(xid, XAResource.TMNOFLAGS);
+            }
             status = Status.STATUS_ACTIVE;
 
         } catch (XAException e) {
@@ -114,10 +125,18 @@
         }
 
         try {
-            xares.end(xid, XAResource.TMSUCCESS);
+            for (Iterator it = xaResources.keySet().iterator(); it.hasNext(); ) {
+                XAResource resource = (XAResource) it.next();
+                XidImpl xid = (XidImpl) xaResources.get(resource);
+                resource.end(xid, XAResource.TMSUCCESS);
+            }
 
             status = Status.STATUS_PREPARING;
-            xares.prepare(xid);
+            for (Iterator it = xaResources.keySet().iterator(); it.hasNext(); ) {
+                XAResource resource = (XAResource) it.next();
+                XidImpl xid = (XidImpl) xaResources.get(resource);
+                resource.prepare(xid);
+            }
             status = Status.STATUS_PREPARED;
 
             status = Status.STATUS_COMMITTING;
@@ -125,7 +144,11 @@
                 Thread distributedThread = new Thread() {
                     public void run() {
                         try {
-                            xares.commit(xid, false);
+                            for (Iterator it = xaResources.keySet().iterator(); it.hasNext(); ) {
+                                XAResource resource = (XAResource) it.next();
+                                XidImpl xid = (XidImpl) xaResources.get(resource);
+                                resource.commit(xid, false);
+                            }
                         } catch (Exception e) {
                             throw new RuntimeException(e.getMessage());
                         }
@@ -138,7 +161,11 @@
                             "Commit from different thread but same XID must not block");
                 }
             } else {
-                xares.commit(xid, false);
+                for (Iterator it = xaResources.keySet().iterator(); it.hasNext(); ) {
+                    XAResource resource = (XAResource) it.next();
+                    XidImpl xid = (XidImpl) xaResources.get(resource);
+                    resource.commit(xid, false);
+                }
             }
             
             status = Status.STATUS_COMMITTED;
@@ -182,10 +209,18 @@
         }
 
         try {
-            xares.end(xid, XAResource.TMFAIL);
+            for (Iterator it = xaResources.keySet().iterator(); it.hasNext(); ) {
+                XAResource resource = (XAResource) it.next();
+                XidImpl xid = (XidImpl) xaResources.get(resource);
+                resource.end(xid, XAResource.TMFAIL);
+            }
 
             status = Status.STATUS_ROLLING_BACK;
-            xares.rollback(xid);
+            for (Iterator it = xaResources.keySet().iterator(); it.hasNext(); ) {
+                XAResource resource = (XAResource) it.next();
+                XidImpl xid = (XidImpl) xaResources.get(resource);
+                resource.rollback(xid);
+            }
             status = Status.STATUS_ROLLEDBACK;
 
         } catch (XAException e) {
@@ -211,7 +246,9 @@
      */
     public void setTransactionTimeout(int seconds) throws SystemException {
         try {
-            xares.setTransactionTimeout(seconds);
+            for (Iterator it = xaResources.keySet().iterator(); it.hasNext(); ) {
+                ((XAResource) it.next()).setTransactionTimeout(seconds);
+            }
         } catch (XAException e) {
             SystemException se = new SystemException(
                     "Unable to set the TransactionTiomeout: XA_ERR=" + e.errorCode);

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/XATest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/XATest.java?rev=819491&r1=819490&r2=819491&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/XATest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/XATest.java Mon Sep 28 10:30:36 2009
@@ -1643,6 +1643,99 @@
             fail("Committed node not visible in this session");
         }
     }
+    
+    /**
+     * Tests two different Sessions in one Transaction
+     * (see JCR-769)
+     */
+    public void testTwoSessionsInOneTransaction() throws Exception {
+        Session otherSuperuser = getHelper().getSuperuserSession();
+        
+        // get user transaction object
+        UserTransactionImpl utx = new UserTransactionImpl(superuser, true);
+        utx.enlistXAResource(otherSuperuser);
+        
+        // start transaction
+        utx.begin();
+
+        Node rootNode = superuser.getRootNode();
+        // add node and save
+        Node n = rootNode.addNode(nodeName1, testNodeType);
+        n.addMixin(mixReferenceable);
+        rootNode.save();
+
+        // assertion: node exists in this session
+        try {
+            superuser.getNodeByUUID(n.getUUID());
+        } catch (ItemNotFoundException e) {
+            fail("New node not visible after save()");
+        }
+
+        // assertion: node does exist in other session
+        try {
+            otherSuperuser.getNodeByUUID(n.getUUID());
+            fail("Uncommitted node visible for other session");
+        } catch (ItemNotFoundException e) {
+            /* expected */
+        }
+
+        // add node with other session and save
+        rootNode = otherSuperuser.getRootNode();
+        Node n1 = rootNode.addNode(nodeName2, testNodeType);
+        n1.addMixin(mixReferenceable);
+        rootNode.save();
+
+        // assertion: node exists in this session
+        try {
+            otherSuperuser.getNodeByUUID(n1.getUUID());
+        } catch (ItemNotFoundException e) {
+            fail("New node not visible after save()");
+        }
+
+        // assertion: node does exist in other session
+        try {
+            superuser.getNodeByUUID(n1.getUUID());
+            fail("Uncommitted node visible for other session");
+        } catch (ItemNotFoundException e) {
+            /* expected */
+        }
+
+        
+        // commit
+        utx.commit();
+
+        // assertion: node exists in this session
+        try {
+            superuser.getNodeByUUID(n.getUUID());
+        } catch (ItemNotFoundException e) {
+            fail("Committed node not visible in this session");
+        }
+
+        // assertion: node also exists in other session
+        try {
+            otherSuperuser.getNodeByUUID(n.getUUID());
+        } catch (ItemNotFoundException e) {
+            fail("Committed node not visible in the other session");
+        }
+
+        // assertion: node1 exists in this session
+        try {
+            superuser.getNodeByUUID(n1.getUUID());
+        } catch (ItemNotFoundException e) {
+            fail("Committed node not visible in this session");
+        }
+
+        // assertion: node1 also exists in other session
+        try {
+            otherSuperuser.getNodeByUUID(n1.getUUID());
+        } catch (ItemNotFoundException e) {
+            fail("Committed node not visible in this session");
+        }
+
+        // logout
+        superuser.logout();
+        otherSuperuser.logout();
+    }
 
     /**
      * Test setting the same property multiple times. Exposes an issue where