package com.ximple.io.dgn7;
|
|
//~--- JDK imports ------------------------------------------------------------
|
|
import java.io.IOException;
|
import java.util.HashMap;
|
import java.util.Map;
|
|
import org.apache.log4j.LogManager;
|
import org.apache.log4j.Logger;
|
|
/**
|
* Lock
|
*
|
* @author Ulysses
|
* @version 0.1
|
* @since 2006/5/18
|
*/
|
public class Lock {
|
Logger logger = LogManager.getLogger("com.ximple.io.dgn7");
|
|
/**
|
* indicates a write is occurring
|
*/
|
int writeLocks = 0;
|
|
/**
|
* if not null a writer is waiting for the lock or is writing.
|
*/
|
Thread writer;
|
|
/**
|
* Thread->Owner map. If empty no read locks exist.
|
*/
|
Map owners = new HashMap();
|
|
/**
|
* If the lock can be read locked the lock will be read and default
|
* visibility for tests
|
*
|
* @return
|
* @throws java.io.IOException
|
*/
|
synchronized boolean canRead() throws IOException {
|
if ((writer != null) && (writer != Thread.currentThread())) {
|
return false;
|
}
|
|
if (writer == null) {
|
return true;
|
}
|
|
if (owners.size() > 1) {
|
return false;
|
}
|
|
return true;
|
}
|
|
/**
|
* If the lock can be read locked the lock will be read and default
|
* visibility for tests
|
*
|
* @return
|
* @throws IOException
|
*/
|
synchronized boolean canWrite() throws IOException {
|
if (owners.size() > 1) {
|
return false;
|
}
|
|
if ((canRead()) && ((writer == Thread.currentThread()) || (writer == null))) {
|
if (owners.isEmpty()) {
|
return true;
|
}
|
|
if (owners.containsKey(Thread.currentThread())) {
|
return true;
|
}
|
}
|
|
return false;
|
}
|
|
/**
|
* Called by shapefileReader before a read is started and before an IOStream
|
* is openned.
|
*
|
* @throws IOException
|
*/
|
public synchronized void lockRead() throws IOException {
|
if (!canRead()) {
|
while ((writeLocks > 0) || (writer != null)) {
|
try {
|
wait();
|
} catch (InterruptedException e) {
|
throw (IOException) new IOException().initCause(e);
|
}
|
}
|
}
|
|
assertTrue("A write lock exists that is owned by another thread", canRead());
|
|
Thread current = Thread.currentThread();
|
Owner owner = (Owner) owners.get(current);
|
|
if (owner != null) {
|
owner.timesLocked++;
|
} else {
|
owner = new Owner(current);
|
owners.put(current, owner);
|
}
|
|
logger.debug("Start Read Lock:" + owner);
|
}
|
|
private void assertTrue(String message, boolean b) {
|
if (!b) {
|
throw new AssertionError(message);
|
}
|
}
|
|
/**
|
* Called by ShapefileReader after a read is complete and after the IOStream
|
* is closed.
|
*/
|
public synchronized void unlockRead() {
|
assertTrue("Current thread does not have a readLock", owners.containsKey(Thread.currentThread()));
|
|
Owner owner = (Owner) owners.get(Thread.currentThread());
|
|
assertTrue("Current thread has " + owner.timesLocked + "negative number of locks", owner.timesLocked > 0);
|
owner.timesLocked--;
|
|
if (owner.timesLocked == 0) {
|
owners.remove(Thread.currentThread());
|
}
|
|
notifyAll();
|
logger.debug("unlock Read:" + owner);
|
}
|
|
/**
|
* Called by ShapefileDataStore before a write is started and before an
|
* IOStream is openned.
|
*
|
* @throws IOException
|
*/
|
public synchronized void lockWrite() throws IOException {
|
Thread currentThread = Thread.currentThread();
|
|
if (writer == null) {
|
writer = currentThread;
|
}
|
|
while (!canWrite()) {
|
try {
|
wait();
|
} catch (InterruptedException e) {
|
throw (IOException) new IOException().initCause(e);
|
}
|
|
if (writer == null) {
|
writer = currentThread;
|
}
|
}
|
|
if (writer == null) {
|
writer = currentThread;
|
}
|
|
assertTrue("The current thread is not the writer", writer == currentThread);
|
assertTrue("There are read locks not belonging to the current thread.", canRead());
|
writeLocks++;
|
logger.debug(currentThread.getName() + " is getting write lock:" + writeLocks);
|
}
|
|
/**
|
* default visibility for tests
|
*/
|
synchronized int getReadLocks(Thread thread) {
|
Owner owner = (Owner) owners.get(thread);
|
|
if (owner == null) {
|
return -1;
|
}
|
|
return owner.timesLocked;
|
}
|
|
public synchronized void unlockWrite() {
|
if (writeLocks > 0) {
|
assertTrue("current thread does not own the write lock", writer == Thread.currentThread());
|
assertTrue("writeLock has already been unlocked", writeLocks > 0);
|
writeLocks--;
|
|
if (writeLocks == 0) {
|
writer = null;
|
}
|
}
|
|
logger.debug("unlock write:" + Thread.currentThread().getName());
|
notifyAll();
|
}
|
|
/**
|
* default visibility for tests
|
*/
|
synchronized boolean ownWriteLock(Thread thread) {
|
return (writer == thread) && (writeLocks > 0);
|
}
|
|
private class Owner {
|
final Thread owner;
|
int timesLocked;
|
|
Owner(Thread owner) {
|
this.owner = owner;
|
timesLocked = 1;
|
}
|
|
public String toString() {
|
return owner.getName() + " has " + timesLocked + " locks";
|
}
|
}
|
}
|