### Eclipse Workspace Patch 1.0 #P jackrabbit-core Index: src/main/java/org/apache/jackrabbit/core/TransactionContext.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/TransactionContext.java (revision 814512) +++ src/main/java/org/apache/jackrabbit/core/TransactionContext.java (working copy) @@ -350,6 +350,6 @@ */ public static boolean isCurrentXid(Xid xid, boolean fallback) { Xid currentXid = (Xid) CURRENT_XID.get(); - return fallback ? true : (currentXid == null || xid == null) ? fallback : Arrays.equals(xid.getGlobalTransactionId(), currentXid.getGlobalTransactionId()); + return (currentXid == null || xid == null) ? fallback : Arrays.equals(xid.getGlobalTransactionId(), currentXid.getGlobalTransactionId()); } } Index: src/main/java/org/apache/jackrabbit/core/state/DefaultISMLocking.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/state/DefaultISMLocking.java (revision 899564) +++ src/main/java/org/apache/jackrabbit/core/state/DefaultISMLocking.java (working copy) @@ -61,8 +61,12 @@ return new WriteLock() { { + Xid currentXid = TransactionContext.getCurrentXid(); + // Mark on the rwLock the current Xid to handle Thread-Deadlocks in XA Environment + rwLock.markActiveXid(currentXid); rwLock.writeLock().acquire(); - rwLock.setActiveXid(TransactionContext.getCurrentXid()); + // After we got a writeLock we will set the ActiveXid + rwLock.setActiveXid(currentXid); } /** @@ -103,16 +107,25 @@ private static final class RWLock extends ReentrantWriterPreferenceReadWriteLock { private Xid activeXid; + private Xid markedXid; /** * Allow reader when there is no active writer, or current thread owns * the write lock (reentrant). */ protected boolean allowReader() { - return TransactionContext.isCurrentXid(activeXid, (activeWriter_ == null || activeWriter_ == Thread.currentThread())); + return TransactionContext.isCurrentXid(activeXid, (activeWriter_ == null || activeWriter_ == Thread.currentThread())); } /** + * Set the Xid to mark it on this RWLock + * @param xid + */ + public void markActiveXid(Xid xid) { + markedXid = xid; + } + + /** * Sets the active Xid * @param xid */ @@ -120,7 +133,8 @@ 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."); + log.warn("Unable to set the ActiveXid while a other one is associated with a different GlobalTransactionId with this RWLock. " + + "Please file a Jira Issue if you see this message and refer to JCR-1334."); return; } } @@ -135,9 +149,9 @@ protected synchronized Signaller endWrite() { --writeHolds_; if (writeHolds_ > 0) { // still being held - return null; + return null; } else { - activeXid = null; + activeXid = null; activeWriter_ = null; if (waitingReaders_ > 0 && allowReader()) { return readerLock_; @@ -148,5 +162,33 @@ } } } + + /** + * {@inheritDoc} + * + * If there is still a active Xid on this RWLock do not allow startWrite + */ + protected synchronized boolean startWrite() { + // Test if we have a activeXid or a markedXid. If not check the activeWriter Thread + boolean allow = TransactionContext.isCurrentXid((activeXid != null) ? activeXid : markedXid, (activeWriter_ == Thread.currentThread())); + if (allow) { + ++writeHolds_; + if (activeWriter_ == null) { + // Set the ActiveWriter to hold it .. could happen if we are in XA Environment + activeWriter_ = Thread.currentThread(); + } + return true; + } else if (writeHolds_ == 0) { + if (activeReaders_ == 0 || (readers_.size() == 1 && readers_.get(Thread.currentThread()) != null)) { + activeWriter_ = Thread.currentThread(); + writeHolds_ = 1; + return true; + } else { + return false; + } + } else { + return false; + } + } } }