package org.jacorb.concurrency;
/*
* JacORB concurrency control service - a free CCS for JacORB
*
* Copyright (C) 1999-2004 LogicLand group, Viacheslav Tararin.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import org.omg.CosConcurrencyControl.LockCoordinator;
import org.omg.CosConcurrencyControl.LockNotHeld;
import org.omg.CosConcurrencyControl.TransactionalLockSet;
import org.omg.CosConcurrencyControl.TransactionalLockSetPOA;
import org.omg.CosConcurrencyControl.lock_mode;
import org.omg.CosTransactions.Coordinator;
import org.omg.CosTransactions.Status;
class TransactionalLockSetImpl extends TransactionalLockSetPOA {
private Hashtable locks = new Hashtable();
private Vector queue = new Vector();
private Vector related = new Vector();
private LockSetFactoryImpl factory;
private boolean is_active = true;
TransactionalLockSetImpl( LockSetFactoryImpl factory ) {
this.factory = factory;
};
public void lock( Coordinator current, lock_mode mode ) {
synchronized( queue ){
check_active();
TransactionCoordinator tc = factory.get_transaction_coordinator(current);
Request rqst = null;
synchronized( tc ){
check_status(tc);
if(attempt_lock( tc, mode )){
return;
}
rqst = new Request();
rqst.state = LockSetFactoryImpl.REQUEST;
rqst.current = tc;
rqst.to_do = Request.LOCK;
rqst.set_mode = mode;
rqst.reset_mode = null;
queue.addElement( rqst );
tc.set_lock_coordinator( this );
}
while( rqst.state == LockSetFactoryImpl.REQUEST ){
try {
queue.wait();
} catch ( Exception e ){
e.printStackTrace( System.out );
throw new org.omg.CORBA.INTERNAL();
}
};
switch( rqst.state ){
case LockSetFactoryImpl.COMMIT :
case LockSetFactoryImpl.NO_TRANS :
throw new org.omg.CORBA.INVALID_TRANSACTION();
case LockSetFactoryImpl.ROLLBACK :
throw new org.omg.CORBA.TRANSACTION_ROLLEDBACK();
}
}
};
public boolean try_lock( Coordinator current, lock_mode mode ) {
synchronized( queue ){
check_active();
TransactionCoordinator tc = factory.get_transaction_coordinator(current);
synchronized( tc ){
check_status(tc);
return attempt_lock( tc, mode );
}
}
};
public void unlock( Coordinator current, lock_mode mode ) throws LockNotHeld {
synchronized( queue ){
check_active();
TransactionCoordinator tc = factory.get_transaction_coordinator(current);
synchronized( tc ){
check_status(tc);
TransactionLocks current_locks = (TransactionLocks)locks.get( tc );
if( current_locks == null ){
throw new LockNotHeld();
}
current_locks.unlock(mode);
}
if( attempt_lock_from_queue() ){
queue.notifyAll();
};
}
};
public void change_mode( Coordinator current, lock_mode held_mode, lock_mode new_mode ) throws LockNotHeld {
synchronized( queue ){
check_active();
TransactionCoordinator tc = factory.get_transaction_coordinator(current);
Request rqst = null;
synchronized( tc ){
check_status(tc);
if(attempt_change( tc, new_mode, held_mode )){
return;
}
rqst = new Request();
rqst.state = LockSetFactoryImpl.REQUEST;
rqst.current = tc;
rqst.to_do = Request.CHANGE;
rqst.set_mode = new_mode;
rqst.reset_mode = held_mode;
queue.addElement( rqst );
tc.get_lock_coordinator( this );
}
while( rqst.state == LockSetFactoryImpl.REQUEST ){
try {
queue.wait();
} catch ( Exception e ){
e.printStackTrace( System.out );
throw new org.omg.CORBA.INTERNAL();
}
};
switch( rqst.state ){
case LockSetFactoryImpl.COMMIT :
case LockSetFactoryImpl.NO_TRANS :
throw new org.omg.CORBA.INVALID_TRANSACTION();
case LockSetFactoryImpl.ROLLBACK :
throw new org.omg.CORBA.TRANSACTION_ROLLEDBACK();
case LockSetFactoryImpl.REJECT :
throw new LockNotHeld();
}
if( attempt_lock_from_queue() ){
queue.notifyAll();
};
}
};
public LockCoordinator get_coordinator( Coordinator which ) {
TransactionCoordinator tc = factory.get_transaction_coordinator( which );
return tc.get_lock_coordinator( this );
};
synchronized void add_related( TransactionalLockSet which ){
related.addElement( which );
};
synchronized boolean attempt_lock( TransactionCoordinator tc, lock_mode mode ){
Enumeration enumeration = locks.elements();
TransactionLocks current_transaction_locks = null;
while( enumeration.hasMoreElements() ){
TransactionLocks lock = (TransactionLocks) enumeration.nextElement();
if( lock.current == tc ){
current_transaction_locks = lock;
continue;
}
if( !lock.no_conflict( mode ) ){
return false;
}
};
if( current_transaction_locks == null ){
current_transaction_locks = new TransactionLocks( tc );
tc.get_lock_coordinator( this );
locks.put( tc, current_transaction_locks );
}
current_transaction_locks.lock( mode );
return true;
};
private void check_status( TransactionCoordinator tc ){
Status status = tc.get_state();
if( status.equals( Status.StatusActive ) ){
return;
} else if( status.equals( Status.StatusPrepared ) ||
status.equals( Status.StatusCommitted ) ||
status.equals( Status.StatusUnknown ) ||
status.equals( Status.StatusNoTransaction ) ||
status.equals( Status.StatusPreparing ) ||
status.equals( Status.StatusCommitting ) ) {
throw new org.omg.CORBA.INVALID_TRANSACTION();
} else if (status.equals( Status.StatusRollingBack ) ||
status.equals( Status.StatusMarkedRollback) ||
status.equals( Status.StatusRolledBack) ) {
throw new org.omg.CORBA.TRANSACTION_ROLLEDBACK();
}
}
private synchronized boolean attempt_lock_from_queue(){
boolean do_recursive = false;
Vector executed = new Vector();
Enumeration enumeration = queue.elements();
while( enumeration.hasMoreElements() ){
Request r = (Request)enumeration.nextElement();
synchronized( r.current ){
try {
check_status( r.current );
} catch ( org.omg.CORBA.INVALID_TRANSACTION e ) {
r.state = LockSetFactoryImpl.NO_TRANS;
executed.addElement( r );
continue;
} catch ( org.omg.CORBA.TRANSACTION_ROLLEDBACK e ) {
r.state = LockSetFactoryImpl.ROLLBACK;
executed.addElement( r );
continue;
}
switch( r.to_do ) {
case Request.LOCK:
if( !attempt_lock( r.current, r.set_mode ) ) {
continue;
}
r.state = LockSetFactoryImpl.SATISFIED;
break;
case Request.CHANGE:
try {
if( !attempt_change( r.current, r.set_mode, r.reset_mode ) ) {
continue;
}
r.state = LockSetFactoryImpl.SATISFIED;
do_recursive = true;
} catch ( LockNotHeld e ) {
r.state = LockSetFactoryImpl.REJECT;
}
break;
}
executed.addElement( r );
}
};
enumeration = executed.elements();
while( enumeration.hasMoreElements() ){
queue.removeElement( enumeration.nextElement() );
}
if( do_recursive ){
attempt_lock_from_queue();
}
return executed.size() > 0;
};
private synchronized boolean attempt_change( TransactionCoordinator tc, lock_mode set_mode, lock_mode reset_mode ) throws LockNotHeld {
TransactionLocks current_locks = (TransactionLocks)locks.get( tc );
if( current_locks == null || !current_locks.is_held( reset_mode ) ){
throw new LockNotHeld();
}
if( attempt_lock( tc, set_mode ) ){
current_locks.unlock( reset_mode );
return true;
}
return false;
};
synchronized void transaction_finished( TransactionCoordinator tc ){
Vector executed = new Vector();
Enumeration enumeration;
boolean do_notify = false;
synchronized( queue ){
enumeration = queue.elements();
while( enumeration.hasMoreElements() ){
Request r = (Request)enumeration.nextElement();
if( r.current == tc ){
r.state = LockSetFactoryImpl.ROLLBACK;
executed.addElement( r );
}
}
if( executed.size() > 0 ) {
enumeration = executed.elements();
while( enumeration.hasMoreElements() ){
queue.removeElement( enumeration.nextElement() );
}
do_notify = true;
}
if( locks.remove( tc ) != null ) {
do_notify = attempt_lock_from_queue()?true:do_notify;
}
if( do_notify ) {
queue.notifyAll();
}
}
if( related.size() > 0 ) {
enumeration = related.elements();
while( enumeration.hasMoreElements() ){
TransactionalLockSet ls = (TransactionalLockSet)enumeration.nextElement();
ls.get_coordinator( tc.get_coordinator() ).drop_locks();
}
}
};
public void print(){
Enumeration enumeration;
System.out.println("\n=============================================================================");
System.out.println(" LOCKS"+locks.size() );
System.out.println("-----------------------------------------------------------------------------");
synchronized ( queue ) {
enumeration = locks.elements();
while( enumeration.hasMoreElements() ){
TransactionLocks r = (TransactionLocks)enumeration.nextElement();
System.out.println( r.toString() );
}
System.out.println("\n-----------------------------------------------------------------------------");
System.out.println(" QUEUE"+queue.size() );
System.out.println("-----------------------------------------------------------------------------");
enumeration = queue.elements();
while( enumeration.hasMoreElements() ){
Request r = (Request)enumeration.nextElement();
System.out.println( r.toString() );
}
};
System.out.println("=============================================================================\n");
};
// public void destroy() throws LockExists {
public void destroy() {
synchronized( queue ){
check_active();
is_active = false;
if( locks.size() > 0 ){
Enumeration enumeration = locks.elements();
while( enumeration.hasMoreElements() ){
TransactionLocks ls = (TransactionLocks)enumeration.nextElement();
if( ls.any_locks() ){
throw new RuntimeException("LockExists");
}
}
}
factory.remove_me( this );
};
};
private void check_active(){
if( !is_active ){
throw new org.omg.CORBA.OBJECT_NOT_EXIST();
}
}
};