/*
* 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.util;
import static org.apache.jackrabbit.data.core.TransactionContext.getCurrentThreadId;
import static org.apache.jackrabbit.data.core.TransactionContext.isSameThreadId;
import EDU.oswego.cs.dl.util.concurrent.ReentrantWriterPreferenceReadWriteLock;
/**
* A reentrant read-write lock 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 XAReentrantWriterPreferenceReadWriteLock 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;
}
}
}
}