/*
* This file is part of the HyperGraphDB source distribution. This is copyrighted software. For permitted
* uses, licensing options and redistribution, please see the LicensingInformation file at the root level of
* the distribution.
*
* Copyright (c) 2005-2010 Kobrix Software, Inc. All rights reserved.
*/
package org.hypergraphdb.storage.bje;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import org.hypergraphdb.HGException;
import org.hypergraphdb.HyperGraph;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.LockNotAvailableException;
import com.sleepycat.je.txn.Locker;
/**
*
* <p>
* A <code>ReadWriteLock</code> implementation backed by the BerkeleyDB locking mechanism. This implementation
* uses the current HGDB transaction as the BDB locker. Only the <code>lock()</code>, <code>unlock()</code>
* and <code>tryLock()</code> methods are actually supported for now.
* </p>
*
* @author Borislav Iordanov
*
*/
//TODO: Not implemented in JE. Calls are dummied
public class BJETxLock implements ReadWriteLock {
private HyperGraph graph;
private DatabaseEntry objectId;
private BJEReadLock readLock = new BJEReadLock();
private BJEWriteLock writeLock = new BJEWriteLock();
// private int getLockerId() {
// try {
// return (int)((TransactionBJEImpl)graph.getTransactionManager().getContext().getCurrent()
// .getStorageTransaction()).getBJETransaction().getId();
// }
// catch (DatabaseException ex) {
// throw new HGException(ex);
// }
// }
//
// private Environment getEnv() {
// return ((TransactionBJEImpl)graph.getTransactionManager().getContext().getCurrent()
// .getStorageTransaction()).getBJEEnvironment();
// }
private class BJEReadLock implements Lock {
Locker lock = null;
ThreadLocal<Integer> readCount = new ThreadLocal<Integer>() {
protected Integer initialValue() {
return 0;
}
};
BJEReadLock() {
}
public synchronized void lock() {
try {
if (readCount.get() == 0) {
// lock = getEnv().getLock(getLockerId(), false, objectId, LockRequestMode.READ);
}
readCount.set(readCount.get() + 1);
}
catch (DatabaseException ex) {
throw new HGException(ex);
}
}
public void lockInterruptibly() throws InterruptedException {
throw new UnsupportedOperationException();
}
public Condition newCondition() {
throw new UnsupportedOperationException();
}
public synchronized boolean tryLock() {
try {
if (readCount.get() == 0) {
// lock = getEnv().getLock(getLockerId(), true, objectId, LockRequestMode.READ);
}
if (lock != null) {
readCount.set(readCount.get() + 1);
return true;
}
else {
return false;
}
}
catch (LockNotAvailableException le) {
return false;
}
catch (DatabaseException ex) {
throw new HGException(ex);
}
}
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
throw new UnsupportedOperationException();
}
public synchronized void unlock() {
try {
if (lock != null) {
int newcnt = readCount.get() - 1;
if (newcnt < 0)
throw new IllegalStateException("Lock already released.");
else if (newcnt == 0) {
// getEnv().putLock(lock);
lock = null;
}
readCount.set(newcnt);
}
}
catch (DatabaseException ex) {
throw new HGException(ex);
}
}
}
private class BJEWriteLock implements Lock {
Locker lock;
ThreadLocal<Integer> writeCount = new ThreadLocal<Integer>() {
protected Integer initialValue() {
return 0;
}
};
BJEWriteLock() {
writeCount.set(new Integer(0));
}
public void lock() {
try {
if (writeCount.get() == 0) {
// lock = getEnv().getLock(getLockerId(), false, objectId, LockRequestMode.WRITE);
}
writeCount.set(writeCount.get() + 1);
}
catch (DatabaseException ex) {
throw new HGException(ex);
}
}
public void lockInterruptibly() throws InterruptedException {
throw new UnsupportedOperationException();
}
public Condition newCondition() {
throw new UnsupportedOperationException();
}
public boolean tryLock() {
try {
if (writeCount.get() == 0) {
// lock = getEnv().getLock(getLockerId(), true, objectId, LockRequestMode.WRITE);
}
if (lock != null) {
writeCount.set(writeCount.get() + 1);
return true;
}
else
return false;
}
catch (LockNotAvailableException le) {
return false;
}
catch (DatabaseException ex) {
throw new HGException(ex);
}
}
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
throw new UnsupportedOperationException();
}
public void unlock() {
try {
int newcnt = writeCount.get() - 1;
if (newcnt < 0) {
throw new IllegalStateException("Lock already released.");
}
else if (newcnt == 0) {
// getEnv().putLock(lock);
lock = null;
}
writeCount.set(newcnt);
}
catch (DatabaseException ex) {
throw new HGException(ex);
}
}
}
public BJETxLock(HyperGraph graph, byte[] objectId) {
this(graph, new DatabaseEntry(objectId));
}
public BJETxLock(HyperGraph graph, DatabaseEntry objectId) {
this.graph = graph;
this.objectId = new DatabaseEntry();
byte[] tmp = new byte[objectId.getData().length];
System.arraycopy(objectId.getData(), 0, tmp, 0, tmp.length);
this.objectId = new DatabaseEntry(tmp);
}
public Lock readLock() {
return readLock;
}
public Lock writeLock() {
return writeLock;
}
public HyperGraph getGraph() {
return graph;
}
public byte[] getObjectId() {
return objectId.getData();
}
}