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 2012/06/27 15:47:45 UTC

svn commit: r1354499 - in /jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal: AbstractJournal.java JournalLock.java

Author: ckoell
Date: Wed Jun 27 13:47:44 2012
New Revision: 1354499

URL: http://svn.apache.org/viewvc?rev=1354499&view=rev
Log:
JCR-3354 The ReadWriteLock in AbstractJournal can create a Deadlock in XA Environment

Added:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/JournalLock.java   (with props)
Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/AbstractJournal.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/AbstractJournal.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/AbstractJournal.java?rev=1354499&r1=1354498&r2=1354499&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/AbstractJournal.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/AbstractJournal.java Wed Jun 27 13:47:44 2012
@@ -30,7 +30,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import EDU.oswego.cs.dl.util.concurrent.ReadWriteLock;
-import EDU.oswego.cs.dl.util.concurrent.ReentrantWriterPreferenceReadWriteLock;
 
 /**
  * Base journal implementation.
@@ -71,7 +70,7 @@ public abstract class AbstractJournal im
      * Journal lock, allowing multiple readers (synchronizing their contents)
      * but only one writer (appending a new entry).
      */
-    private final ReadWriteLock rwLock = new ReentrantWriterPreferenceReadWriteLock();
+    private final ReadWriteLock rwLock = new JournalLock();
 
     /**
      * The path of the local revision file on disk. Configurable through the repository.xml.

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/JournalLock.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/JournalLock.java?rev=1354499&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/JournalLock.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/JournalLock.java Wed Jun 27 13:47:44 2012
@@ -0,0 +1,130 @@
+/*
+ * 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.core.journal;
+
+import static org.apache.jackrabbit.core.TransactionContext.getCurrentThreadId;
+import static org.apache.jackrabbit.core.TransactionContext.isSameThreadId;
+import EDU.oswego.cs.dl.util.concurrent.ReentrantWriterPreferenceReadWriteLock;
+
+/**
+ * A reentrant read-write lock used by the Journal for synchronization. 
+ * Unlike a normal reentrant lock, this one allows the lock
+ * to be re-entered not just by a thread that's already holding the lock but
+ * by any thread within the same transaction.
+ */
+public class JournalLock extends ReentrantWriterPreferenceReadWriteLock {
+    
+	private Object activeWriter;
+    
+    /**
+     * {@inheritDoc}
+     */
+    protected boolean allowReader() {
+        Object currentId = getCurrentThreadId();
+        return (activeWriter == null && waitingWriters_ == 0) || isSameThreadId(activeWriter, currentId);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected synchronized boolean startWrite() {
+    	Object currentId = getCurrentThreadId();
+        if (activeWriter != null && isSameThreadId(activeWriter, currentId)) { // already held; re-acquire
+        	++writeHolds_;
+            return true;
+        } else if (writeHolds_ == 0) {
+        	if (activeReaders_ == 0 || (readers_.size() == 1 && readers_.get(currentId) != null)) {
+        		activeWriter = currentId;
+        		writeHolds_ = 1;
+        		return true;
+        	} else {
+        		return false;
+        	}
+        } else {
+        	return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected synchronized Signaller endWrite() {
+        --writeHolds_;
+        if (writeHolds_ > 0) {  // still being held
+        	return null;
+        } else {
+        	activeWriter = null;
+            if (waitingReaders_ > 0 && allowReader()) {
+                return readerLock_;
+            } else if (waitingWriters_ > 0) {
+                return writerLock_;
+            } else {
+                return null;
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+	@SuppressWarnings("unchecked")
+	protected synchronized boolean startRead() {
+		Object currentId = getCurrentThreadId();
+	    Object c = readers_.get(currentId);
+	    if (c != null) { // already held -- just increment hold count
+	    	readers_.put(currentId, new Integer(((Integer)(c)).intValue()+1));
+	    	++activeReaders_;
+	    	return true;
+	    } else if (allowReader()) {
+	    	readers_.put(currentId, IONE);
+	    	++activeReaders_;
+	    	return true;
+	    } else {
+	    	return false;
+	    }
+	}
+	
+    /**
+     * {@inheritDoc}
+     */
+	@SuppressWarnings("unchecked")
+	protected synchronized Signaller endRead() {
+		Object currentId = getCurrentThreadId();
+	    Object c = readers_.get(currentId);
+	    if (c == null) {
+	    	throw new IllegalStateException();
+	    }
+	    --activeReaders_;
+	    if (c != IONE) { // more than one hold; decrement count
+	    	int h = ((Integer)(c)).intValue()-1;
+	    	Integer ih = (h == 1)? IONE : new Integer(h);
+	    	readers_.put(currentId, ih);
+	    	return null;
+	    } else {
+	    	readers_.remove(currentId);
+	    
+	    	if (writeHolds_ > 0) { // a write lock is still held
+	    		return null;
+	    	} else if (activeReaders_ == 0 && waitingWriters_ > 0) {
+	    		return writerLock_;
+	    	} else  {
+	    		return null;
+	    	}
+	    }
+	}
+
+}
\ No newline at end of file

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/JournalLock.java
------------------------------------------------------------------------------
    svn:eol-style = native