package org.jboss.cache.lock;
import EDU.oswego.cs.dl.util.concurrent.Sync;
import org.jboss.cache.TreeCache;
import org.jboss.cache.Fqn;
import org.jboss.logging.Logger;
import java.util.Collection;
import java.util.List;
import java.util.ArrayList;
public class IdentityLock
{
private static Logger log = Logger.getLogger(IdentityLock.class);
private LockStrategy lock_;
private LockMap map_;
private TreeCache cache_;
private transient Fqn fqn;
public IdentityLock(TreeCache cache, Fqn fqn)
{
cache_ = cache;
this.fqn=fqn;
if(cache_ == null) {
if(log.isDebugEnabled()) {
log.debug("Cache instance is null. Use default lock strategy");
}
lock_ = LockStrategyFactory.getLockStrategy();
} else {
lock_ = LockStrategyFactory.getLockStrategy(cache_.getIsolationLevelClass());
}
map_ = new LockMap();
cache_ = cache;
}
public Fqn getFqn() {
return fqn;
}
public List getReaderOwners()
{
return map_.readerOwners();
}
public Object getWriterOwner()
{
return map_.writerOwner();
}
public boolean acquireWriteLock(Object caller, long timeout) throws LockingException, TimeoutException, InterruptedException
{
boolean rc;
if (caller == null) {
throw new IllegalArgumentException("acquireWriteLock(): null caller");
}
synchronized(this) {
if (map_.isOwner(caller, LockMap.OWNER_WRITE)) {
if (log.isTraceEnabled())
log.trace("acquireWriteLock(): caller already owns lock for " + fqn + " (caller=" + caller + ")");
return false; }
}
if (map_.isOwner(caller, LockMap.OWNER_READ)) {
Sync wLock = null;
try {
if(log.isTraceEnabled())
log.trace("upgrading RL to WL for " + caller + ", timeout=" + timeout + ", locks: " + map_.printInfo());
wLock = lock_.upgradeLockAttempt(timeout);
} catch (UpgradeException ue) {
String errStr="acquireWriteLock(): lock upgrade failed for " + fqn + " (caller=" + caller + ")";
log.error(errStr, ue);
throw new UpgradeException(errStr, ue);
}
if (wLock == null) {
release(caller); map_.removeReader(caller);
String errStr="upgrade lock for " + fqn + " could not be acquired after " + timeout + " ms." +
" Lock map ownership " + map_.printInfo() + " (caller=" + caller + ")";
log.error(errStr);
throw new UpgradeException(errStr);
}
try {
if (log.isTraceEnabled())
log.trace("upgrading lock for " + fqn);
map_.upgrade(caller);
} catch (OwnerNotExistedException ex) {
throw new UpgradeException("Can't upgrade lock to WL for " + fqn + ", error in LockMap.upgrade(): " + ex);
}
}
else {
rc = lock_.writeLock().attempt(timeout);
if (rc == false) {
String errStr = "write lock for " + fqn + " could not be acquired after " + timeout + " ms. " +
"Locks: " + map_.printInfo() + " (caller=" + caller + ", lock info: " + toString(true) + ")";
log.error(errStr);
throw new TimeoutException(errStr);
}
map_.addWriter(caller);
}
return true;
}
public boolean acquireReadLock(Object caller, long timeout) throws LockingException, TimeoutException, InterruptedException
{
boolean rc;
if (caller == null) {
throw new IllegalArgumentException("owner is null");
}
synchronized(this) {
if (map_.isOwner(caller, LockMap.OWNER_ANY)) {
if (log.isTraceEnabled())
log.trace("acquireReadLock(): caller " + caller + " already owns lock for " + fqn);
return false; }
}
rc = lock_.readLock().attempt(timeout);
if (rc == false) {
String errStr = "read lock for " + fqn + " could not be acquired by " + caller +
" after " + timeout + " ms. " + "Locks: " + map_.printInfo() + ", lock info: " + toString(true);
log.error(errStr);
throw new TimeoutException(errStr);
}
map_.addReader(caller); return true;
}
public void release(Object caller)
{
if (caller == null) {
throw new IllegalArgumentException("IdentityLock.release(): null owner object.");
}
synchronized(this) {
if (map_.isOwner(caller, LockMap.OWNER_READ)) {
map_.removeReader(caller);
lock_.readLock().release();
}
else if (map_.isOwner(caller, LockMap.OWNER_WRITE)) {
map_.removeWriter(caller);
lock_.writeLock().release();
}
}
}
public void releaseAll()
{
Object obj = null;
Collection col = null;
if ((obj = map_.writerOwner()) != null) {
lock_.writeLock().release();
map_.removeWriter(obj);
}
if ((col = map_.readerOwners()).size() != 0) {
java.util.Iterator it = col.iterator();
while (it.hasNext()) {
lock_.readLock().release();
}
col.clear();
}
}
public void releaseForce()
{
releaseAll();
}
public boolean isReadLocked()
{
return (map_.readerOwners().size() != 0);
}
public boolean isWriteLocked()
{
return (map_.writerOwner() != null);
}
public boolean isLocked()
{
return isReadLocked() || isWriteLocked();
}
public boolean isOwner(Object o)
{
return map_.isOwner(o, LockMap.OWNER_ANY);
}
public String toString()
{
return toString(false);
}
public String toString(boolean print_lock_details)
{
StringBuffer sb=new StringBuffer();
toString(sb, print_lock_details);
return sb.toString();
}
public void toString(StringBuffer sb)
{
toString(sb, false);
}
public synchronized void toString(StringBuffer sb, boolean print_lock_details)
{
boolean printed_read_owners=false;
Collection read_owners=lock_ != null ? new ArrayList(getReaderOwners()) : null;
if(read_owners != null && read_owners.size() > 0) {
sb.append("read owners=").append(read_owners);
printed_read_owners=true;
}
else
read_owners=null;
Object write_owner=lock_ != null ? getWriterOwner() : null;
if(write_owner != null) {
if(printed_read_owners)
sb.append(", ");
sb.append("write owner=").append(write_owner);
}
if(read_owners == null && write_owner == null)
{
sb.append("<unlocked>");
}
if(print_lock_details)
{
sb.append(" (").append(lock_.toString()).append(")");
}
}
}