package com.sleepycat.je.latch;
import java.util.concurrent.locks.ReentrantLock;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.dbi.EnvironmentImpl;
import de.ovgu.cide.jakutil.*;
/**
* Java5LatchImpl provides an implementation of the Latch interface. By using
* a wrapper class we can avoid link errors when we run in Java 1.4 JVMs.
* LatchSupport.java will only reference this class if it knows that the
* ReentrantLock class is available at runtime through Class.forName().
* LatchSupport only references this class through the Latch interface and only
* constructs an instance using
* Class.forName("Java5LatchImpl").newInstance();
*/
class Java5LatchImpl implements Latch {
static private class JEReentrantLock extends ReentrantLock {
JEReentrantLock( boolean fair){
super(fair);
}
protected Thread getOwner(){
return super.getOwner();
}
}
private JEReentrantLock lock;
private String name;
Java5LatchImpl(){
lock=new JEReentrantLock(EnvironmentImpl.getFairLatches());
}
/**
* Set the latch name, used for latches in objects instantiated from
* the log.
*/
public void setName( String name){
this.name=name;
}
/**
* Acquire a latch for exclusive/write access.
* <p>Wait for the latch if some other thread is holding it. If there are
* threads waiting for access, they will be granted the latch on a FIFO
* basis. When the method returns, the latch is held for exclusive
* access.</p>
* @throws LatchException if the latch is already held by the calling
* thread.
*/
public void acquire() throws DatabaseException {
try {
if (lock.isHeldByCurrentThread()) {
this.hook417();
throw new LatchException(name + " already held");
}
this.hook416();
lock.lock();
assert noteLatch();
}
finally {
assert EnvironmentImpl.maybeForceYield();
}
}
/**
* Acquire a latch for exclusive/write access, but do not block if it's not
* available.
* @return true if the latch was acquired, false if it is not available.
* @throws LatchException if the latch is already held by the calling
* thread.
*/
public boolean acquireNoWait() throws LatchException {
try {
if (lock.isHeldByCurrentThread()) {
this.hook418();
throw new LatchException(name + " already held");
}
boolean ret=lock.tryLock();
if (ret) {
assert noteLatch();
this.hook419();
}
else {
this.hook420();
}
return ret;
}
finally {
assert EnvironmentImpl.maybeForceYield();
}
}
/**
* Release the latch. If there are other thread(s) waiting for the latch,
* one is woken up and granted the latch. If the latch was not owned by
* the caller, just return;
*/
public void releaseIfOwner(){
doRelease(false);
}
/**
* Release the latch. If there are other thread(s) waiting for the latch,
* they are woken up and granted the latch.
* @throws LatchNotHeldException if the latch is not currently held.
*/
public void release() throws LatchNotHeldException {
if (doRelease(true)) {
throw new LatchNotHeldException(name + " not held");
}
}
/**
* Do the work of releasing the latch. Wake up any waiters.
* @returns true if this latch was not owned by the caller.
*/
private boolean doRelease( boolean checkHeld){
try {
if (!lock.isHeldByCurrentThread()) {
return true;
}
lock.unlock();
this.hook421();
assert unNoteLatch(checkHeld);
}
catch ( IllegalMonitorStateException IMSE) {
return true;
}
return false;
}
/**
* Return true if the current thread holds this latch.
* @return true if we hold this latch. False otherwise.
*/
public boolean isOwner(){
return lock.isHeldByCurrentThread();
}
/**
* Used only for unit tests.
* @return the thread that currently holds the latch for exclusive access.
*/
public Thread owner(){
return lock.getOwner();
}
/**
* Return the number of threads waiting.
* @return the number of threads waiting for the latch.
*/
public int nWaiters(){
return lock.getQueueLength();
}
/**
* Formats a latch owner and waiters.
*/
public String toString(){
return lock.toString();
}
/**
* Only call under the assert system. This records latching by thread.
*/
private boolean noteLatch() throws LatchException {
return LatchSupport.latchTable.noteLatch(this);
}
/**
* Only call under the assert system. This records latching by thread.
*/
private boolean unNoteLatch( boolean checkHeld){
if (checkHeld) {
return LatchSupport.latchTable.unNoteLatch(this,name);
}
else {
LatchSupport.latchTable.unNoteLatch(this,name);
return true;
}
}
protected void hook416() throws DatabaseException {
}
protected void hook417() throws DatabaseException {
}
protected void hook418() throws LatchException {
}
protected void hook419() throws LatchException {
}
protected void hook420() throws LatchException {
}
protected void hook421() throws IllegalMonitorStateException {
}
}