/cs/faculty/cappello/z/jicos/framework/source/edu/ucsb/cs/jicos/services/Hsp.java |
package edu.ucsb.cs.jicos.services;
import edu.ucsb.cs.jicos.admin.AdministrableHsp;
import edu.ucsb.cs.jicos.foundation.*;
import edu.ucsb.cs.jicos.services.StateConfig;
import edu.ucsb.cs.jicos.services.commands.*;
import edu.ucsb.cs.jicos.services.external.services.CollectorManager;
import edu.ucsb.cs.jicos.services.external.services.TaskExternal;
import edu.ucsb.cs.jicos.utilities.*;
import java.net.InetAddress;
import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.RMISecurityManager;
import java.rmi.registry.Registry;
import java.sql.*;
import java.util.*;
public final class Hsp extends ServiceImpl implements ClientToHsp, AdministrableHsp
{
public static String SERVICE_NAME = "Jicos";
static final int COMPUTE = 0;
static final int GETRESULT = 1;
static final int LOGIN = 2;
static final int LOGOUT = 3;
static final int SETCOMPUTATION = 4;
private static final Class[][] command2DepartmentArray =
{
{
AddServiceTaskStats.class,
GetServiceName.class,
GetTaskServer.class,
PutResult.class,
Ready.class,
UpdateTaskServerState.class
}
};
private static final CommandSynchronous SHUTDOWN_COMMAND = new Shutdown();
private final static RemoteExceptionHandler remoteExceptionHandler = new
JicosRemoteExceptionHandler();
private Department[] departments = { ServiceImpl.ASAP_DEPARTMENT };
private int nTaskServers;
private int nHosts;
private TopologyManager topologyManager = new TopologyManager( proxyManager() );
private List taskServerTree = new ArrayList();
private Service rootTaskServer;
private TaskServerProxy rootTaskServerProxy;
private Map service2TaskServerDataMap = new HashMap();
private Map externalServiceProviderMap = new HashMap();
private ClientProxy clientProxy;
private Qu clientQ = new Qu();
private Qu loginQ = new Qu();
private ProtocolChecker protocolChecker = new ProtocolChecker();
private SessionHSP session;
private short computationId;
private TaskId currentTask;
private Object value;
private ResultTable resultTable = new ResultTable();
private ServiceTaskStats hspTaskStats = new ServiceTaskStats(serviceName());
private Invoice invoice;
private int pendingResults;
private boolean isJicosException;
private int nWaitingTaskServers;
private StateConfig stateConfig = null;
private boolean loadingState=false;
public Hsp() throws RemoteException, AlreadyBoundException
{
super ( command2DepartmentArray );
super.setService( this );
super.setDepartments( departments );
CollectorManager.startCollectors( this );
LogManager.getLogger( this ).log( LogManager.INFO, "Hsp has been constructed." );
TaskServer root = new TaskServer( this, Task.class );
Registry registry = RegistrationManager.locateRegistry();
registry.bind( TaskServer.SERVICE_NAME, root );
}
public synchronized void addServiceTaskStats ( List serviceTaskStats )
{
hspTaskStats.addAll ( serviceTaskStats );
notify();
}
private void check4Exception( Object value )
throws ComputeException, JicosException
{
String message = "";
if ( value instanceof Exception
|| isJicosException
)
{
try
{
logout();
}
catch ( Exception ignore )
{
message += "Logout failed. \n";
}
Exception exception = (Exception) value;
System.out.println("Hsp: check4Exception: Exception detected.");
exception.printStackTrace();
message += ((Throwable) exception).toString();
if ( isJicosException )
{
isJicosException = false;
JicosException e = new JicosException( message );
e.setStackTrace( ((Throwable) exception).getStackTrace() );
throw e;
}
else
{
ComputeException e = new ComputeException( message );
e.setStackTrace( ((Throwable) exception).getStackTrace() );
throw e;
}
}
}
public synchronized Object compute( Task task )
throws ComputeException, JicosException, RemoteException
{
String message = protocolChecker.check( ProtocolChecker.COMPUTE );
if ( message != null )
{
throw new IllegalStateException( message );
}
pendingResults++;
spawnTask( task );
currentTask = task.getTaskId();
try
{
wait();
}
catch( InterruptedException ignore ) {}
check4Exception( value );
currentTask = null;
return value;
}
public void exceptionHandler( Exception exception )
{
Result result = new Result( null, exception, 0 );
putResult( null, result );
}
public int getPendingResults() { return pendingResults; }
public ProtocolChecker getProtocolChecker() { return protocolChecker; }
public Result getResult()
throws ComputeException, JicosException, RemoteException
{
String msg;
msg = "Checking protocol.";
LogManager.getLogger( this ).config( msg );
String message = protocolChecker.check( ProtocolChecker.GETRESULT );
if ( message != null )
{
throw new IllegalStateException( message );
}
Result result = resultTable.remove();
msg = "Critical Path Time: " + String.valueOf( result.getCriticalPathTime() );
LogManager.getLogger( this ).config( msg );
Object value = result.getValue();
check4Exception( value );
return result;
}
public synchronized SessionInfo getSessionInfo()
{
return ( session == null ) ? null : session.getSessionInfo();
}
public HspState getState()
{
return new HspState( serviceName(), clientQ, nHosts, nTaskServers );
}
private void initClient( ServiceName serviceName,
ClientProfile clientProfile,
Environment environment
)
{
String message = protocolChecker.check( ProtocolChecker.LOGIN );
if ( message != null )
{
throw new IllegalStateException( message );
}
if ( environment == null )
{
message = "Login error: Environment parameter may not be null.";
throw new IllegalArgumentException( message );
}
currentTask = null;
value = null;
resultTable.clear();
hspTaskStats.clear();
invoice = null;
session = new SessionHSP( environment );
clientProxy = new ClientProxy( serviceName, this, remoteExceptionHandler);
if ( rootTaskServer != null )
{
Command command = new LoginClient( session.getSessionInfo() );
rootTaskServerProxy.execute( command );
}
else
{
System.out.println("Hsp: login: rootTaskServer: == null");
}
}
public void login( ServiceName serviceName,
ClientProfile clientProfile,
Environment environment
)
{
synchronized( this )
{
clientQ.add( clientProfile );
loginQ.add( serviceName );
if ( loginQ.size() <= 1 )
{
initClient( serviceName, clientProfile, environment );
return;
}
}
synchronized( serviceName )
{
try
{
serviceName.wait();
}
catch( InterruptedException ignore ) {}
}
synchronized( this )
{
initClient( serviceName, clientProfile, environment );
return;
}
}
public synchronized Invoice logout() throws RemoteException
{
String message = protocolChecker.check( ProtocolChecker.LOGOUT );
if ( message != null )
{
throw new IllegalStateException( message );
}
if ( invoice != null )
{
session = null;
return invoice;
}
if ( session == null )
{
return null;
}
long stopTime = System.currentTimeMillis();
Command command = new LogoutClient();
rootTaskServerProxy.execute( command );
try
{
wait();
}
catch ( InterruptedException ignore ) {}
long startTime = session.getStartTime();
session = null;
value = null;
resultTable.clear();
clientProxy.kill();
clientProxy = null;
clientQ.remove();
loginQ.remove();
if ( loginQ.size() > 0 )
{
ServiceName serviceName = (ServiceName) loginQ.get();
synchronized( serviceName )
{
serviceName.notify();
}
}
String debugMessage = "Logged out client.";
LogManager.getLogger( this ).fine( debugMessage );
return new Invoice ( startTime, stopTime, hspTaskStats );
}
public synchronized void putResult( TaskId taskId, Result result )
{
if ( taskId == null )
{
isJicosException = true;
}
if (
currentTask != null
&& (
taskId == null
|| taskId.computationEquals( currentTask )
)
)
{
value = result.getValue();
notify();
}
else
{
ResultId key = new ResultId( taskId );
resultTable.put( key, result );
}
pendingResults--;
}
public synchronized TaskServerInfo registerTaskServer( ServiceName serviceName, Class taskClass )
{
assert serviceName != null;
assert taskClass != null;
LogManager.getLogger(this).log(LogManager.INFO, "Registering: " + serviceName.toStringWithSpace() );
TaskServerServiceInfo taskServerServiceInfo = new TaskServerServiceInfo( serviceName, taskClass );
TaskServerServiceInfo[] neighbors = topologyManager.add( taskServerServiceInfo );
Service taskServer = serviceName.service();
TaskServerProxy taskServerProxy = new TaskServerProxy( taskServer, this, remoteExceptionHandler );
addProxy( serviceName, taskServerProxy );
service2TaskServerDataMap.put( taskServer, new TaskServerData( serviceName ) );
if ( rootTaskServer == null )
{
rootTaskServer = taskServer;
rootTaskServerProxy = taskServerProxy;
}
nTaskServers++;
if ( TaskExternal.class.isAssignableFrom( taskClass ) )
{
externalServiceProviderMap.put( taskClass, taskServer );
if ( nTaskServers > 1 )
{
Command command = new UpdateExternalServiceProviderMap( taskClass, taskServer, taskServer );
rootTaskServerProxy.execute( command );
}
}
return new TaskServerInfo( neighbors, externalServiceProviderMap );
}
Service rootTaskServer() { return rootTaskServer; }
public synchronized ResultId setComputation( Task task )
{
String message = protocolChecker.check( ProtocolChecker.SETCOMPUTATION );
if ( message != null )
{
throw new IllegalStateException( message );
}
pendingResults++;
spawnTask( task );
return new ResultId( task.getTaskId() );
}
private void spawnTask( Task task )
{
task.init( session.getStartTime(), computationId++ );
task.setTaskServer( rootTaskServer );
task.taskServerServiceName( ((ServiceImpl) rootTaskServer).serviceName() );
Command command = new Spawn( task );
rootTaskServerProxy.execute( command );
}
public void updateTaskServerState( Service taskServer, int nHosts )
{
TaskServerData taskServerData = (TaskServerData) service2TaskServerDataMap.get( taskServer );
taskServerData.setNHosts( nHosts );
}
public Administrable[] getChildren()
{
return null;
}
public CurrentState getCurrentState()
{
return null;
}
public void shutdown()
{
LogManager.getLogger( this ).log( LogManager.INFO, "Hsp: shutting down root taskserver." );
try
{
rootTaskServerProxy.execute( SHUTDOWN_COMMAND, remoteExceptionHandler );
}
catch ( Exception ignore ) {}
}
public void startup()
{
}
public synchronized void saveState( StateConfig sconf ) {
stateConfig = sconf;
loadingState = false;
nWaitingTaskServers = nTaskServers;
System.out.println( "HSP:saveState:nTaskServers=" + nTaskServers );
Command cmdPause = new Pause();
try {
System.out.println( "HSP:Broadcasting pause." );
broadcast( cmdPause, this );
} catch (Exception ignore)
{
ignore.printStackTrace();
}
}
public synchronized void loadState( StateConfig sconf ) {
stateConfig = sconf;
loadingState = true;
nWaitingTaskServers = nTaskServers;
System.out.println( "HSP:loadState:nTaskServers=" + nTaskServers );
Command cmdPause = new Pause();
try {
System.out.println( "HSP:Broadcasting pause." );
broadcast( cmdPause, this );
} catch (Exception ignore)
{
ignore.printStackTrace();
}
String message = protocolChecker.check( ProtocolChecker.SETCOMPUTATION );
System.out.println( "HSP:Set to computation state." );
}
public synchronized void readyState() {
nWaitingTaskServers--;
System.out.println( "HSP:readyState:nWaitingTaskServers=" +
nWaitingTaskServers );
if( nWaitingTaskServers==0 ) {
if( loadingState ) {
System.out.println( "HSP:readyState:Loading HSP state with ID:" +
stateConfig.id );
try {
Class.forName(stateConfig.driver);
Connection con = DriverManager.getConnection(stateConfig.dsn, stateConfig.user, stateConfig.pass);
PreparedStatement ps =
con.prepareStatement("SELECT data FROM hsp_state WHERE id=?");
ps.setString(1, stateConfig.id );
ResultSet rs = ps.executeQuery();
if( rs != null && rs.next() ) {
byte[] bytes = rs.getBytes(1);
Vector dataToLoad = (Vector)((java.rmi.MarshalledObject)bytesToObject( bytes )).get();
ResultTable resTable = (ResultTable)dataToLoad.get(0);
resultTable.clear();
Iterator iter = resTable.values().iterator();
while( iter.hasNext() ) {
Result result = (Result)iter.next();
resultTable.put( result.getId(), result );
}
pendingResults = ((Integer)dataToLoad.get(1)).intValue();
rs.close();
} else {
System.err.println( "HSP: Could not load data from DB with ID="
+ stateConfig.id );
}
ps.close();
}
catch (Exception ignore) {
ignore.printStackTrace();
}
Command cmdLoadState = new LoadState( stateConfig );
try {
System.out.println( "HSP:readyState:Broadcasting load command." );
broadcast( cmdLoadState, this );
} catch( Exception ignore )
{
ignore.printStackTrace();
}
} else {
Command cmdSaveState = new SaveState( stateConfig );
System.out.println( "TaskServer:Saving state to: " + stateConfig.dsn );
try {
Class.forName(stateConfig.driver);
} catch (ClassNotFoundException cnfe) {
System.err.println("Couldn"t find driver class. Make sure jar is in classpath:");
cnfe.printStackTrace();
return;
}
try {
Connection con = DriverManager.getConnection(stateConfig.dsn, stateConfig.user, stateConfig.pass);
PreparedStatement ps =
con.prepareStatement("DELETE FROM hsp_state WHERE id=?");
ps.setString(1, stateConfig.id);
ps.executeUpdate();
ps.close();
ps = con.prepareStatement("DELETE FROM application_state WHERE id=?");
ps.setString(1, stateConfig.id);
ps.executeUpdate();
ps.close();
ps =
con.prepareStatement("INSERT INTO hsp_state (id, data) VALUES (?, ?)");
ps.setString(1, stateConfig.id );
System.out.println( "Storing state to database with ID: " +
stateConfig.id );
Vector dataToStore = new Vector();
dataToStore.add( resultTable );
dataToStore.add( new Integer( pendingResults ));
java.rmi.MarshalledObject marshalledData =
new java.rmi.MarshalledObject(dataToStore);
ps.setBytes(2, objectToBytes( marshalledData ));
int n = ps.executeUpdate();
ps.close();
ps =
con.prepareStatement("INSERT INTO application_state (id, data) VALUES (?, ?)");
ps.setString(1, stateConfig.id );
System.out.println( "Storing state to database with ID: " +
stateConfig.id );
dataToStore = new Vector();
if( session == null ) {
System.err.println(
"No state to save. Sending saveState command anyway to wake taskservers." );
} else {
dataToStore.add( session.getSessionInfo().getEnvironment() );
}
marshalledData =
new java.rmi.MarshalledObject(dataToStore);
ps.setBytes(2, objectToBytes( marshalledData ));
n = ps.executeUpdate();
ps.close();
System.out.println( "HSP:readyState:Broadcasting save command." );
broadcast( cmdSaveState, this );
System.out.println( "HSP:readyState:state stored." );
} catch( Exception ignore )
{
ignore.printStackTrace();
}
}
}
}
public static void main(String[] args) throws RemoteException,
AlreadyBoundException {
if ((1 == args.length) && ("-help".equals(args[0]))) {
System.out.println("Usage: <java> " + Hsp.class.getName()
+ " [#hosts]" );
System.exit(0);
}
System.setSecurityManager(new RMISecurityManager());
Property.loadProperties(args);
Property.load(Hsp.class);
Service jicos = new Hsp();
Registry registry = RegistrationManager.locateRegistry();
registry.bind(SERVICE_NAME, jicos);
if (args.length == 0) {
return;
}
Service taskServer = ((Hsp) jicos).rootTaskServer();
int $Hosts = Integer.parseInt(args[0]);
for (int i = 0; i < $Hosts; i++)
{
new Host( taskServer, false, 1 );
}
System.err.flush();
ServiceName serviceName = new ServiceName(jicos);
System.out.println("There is now an HSP at "
+ serviceName.toStringWithSpace() + " ....");
System.out.flush();
}
}