### Eclipse Workspace Patch 1.0 #P jackrabbit-core Index: src/main/java/org/apache/jackrabbit/core/journal/JournalLock.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/journal/JournalLock.java (revision 0) +++ src/main/java/org/apache/jackrabbit/core/journal/JournalLock.java (working copy) @@ -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 Index: src/main/java/org/apache/jackrabbit/core/journal/JournalLock.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/journal/JournalLock.java (revision 0) +++ src/main/java/org/apache/jackrabbit/core/journal/JournalLock.java (working copy) Property changes on: src/main/java/org/apache/jackrabbit/core/journal/JournalLock.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: src/main/java/org/apache/jackrabbit/core/journal/AbstractJournal.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/journal/AbstractJournal.java (revision 1352440) +++ src/main/java/org/apache/jackrabbit/core/journal/AbstractJournal.java (working copy) @@ -30,7 +30,6 @@ 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 @@ * 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.