### 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) @@ -44,7 +44,7 @@ * The internal read-write lock. */ private final RWLock rwLock = new RWLock(); - + /** * {@inheritDoc} */ @@ -61,8 +61,15 @@ return new WriteLock() { { - rwLock.writeLock().acquire(); - rwLock.setActiveXid(TransactionContext.getCurrentXid()); + // sync Block to prevent race conditions + synchronized (this) { + // Mark on the rwLock the current Xid to handle Thread-Deadlocks in XA Environment + Xid currentXid = TransactionContext.getCurrentXid(); + rwLock.markCurrentXid(currentXid); + rwLock.writeLock().acquire(); + // After we got a writeLock we will set the ActiveXid + rwLock.setActiveXid(currentXid); + } } /** @@ -103,16 +110,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 markCurrentXid(Xid xid) { + markedXid = xid; + } + + /** * Sets the active Xid * @param xid */ @@ -120,7 +136,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 +152,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 +165,33 @@ } } } + + /** + * {@inheritDoc} + * + * If there is still a activeXid with a other GlobalTransactionId startWrite will not be allowed + */ + 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; + } + } } }