Package xcat.mobile.coordinator

Source Code of xcat.mobile.coordinator.AppCoordinatorImpl

/*
* Indiana University Extreme! Lab Software License, Version 1.2
*
* Copyright (C) 2002 The Trustees of Indiana University.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1) All redistributions of source code must retain the above
*    copyright notice, the list of authors in the original source
*    code, this list of conditions and the disclaimer listed in this
*    license;
*
* 2) All redistributions in binary form must reproduce the above
*    copyright notice, this list of conditions and the disclaimer
*    listed in this license in the documentation and/or other
*    materials provided with the distribution;
*
* 3) Any documentation included with all redistributions must include
*    the following acknowledgement:
*
*      "This product includes software developed by the Indiana
*      University Extreme! Lab.  For further information please visit
*      http://www.extreme.indiana.edu/"
*
*    Alternatively, this acknowledgment may appear in the software
*    itself, and wherever such third-party acknowledgments normally
*    appear.
*
* 4) The name "Indiana Univeristy" or "Indiana Univeristy
*    Extreme! Lab" shall not be used to endorse or promote
*    products derived from this software without prior written
*    permission from Indiana University.  For written permission,
*    please contact http://www.extreme.indiana.edu/.
*
* 5) Products derived from this software may not use "Indiana
*    Univeristy" name nor may "Indiana Univeristy" appear in their name,
*    without prior written permission of the Indiana University.
*
* Indiana University provides no reassurances that the source code
* provided does not infringe the patent or any other intellectual
* property rights of any other entity.  Indiana University disclaims any
* liability to any recipient for claims brought by any other entity
* based on infringement of intellectual property rights or otherwise.
*
* LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH
* NO WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA
* UNIVERSITY GIVES NO WARRANTIES AND MAKES NO REPRESENTATION THAT
* SOFTWARE IS FREE OF INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR
* OTHER PROPRIETARY RIGHTS.  INDIANA UNIVERSITY MAKES NO WARRANTIES THAT
* SOFTWARE IS FREE FROM "BUGS", "VIRUSES", "TROJAN HORSES", "TRAP
* DOORS", "WORMS", OR OTHER HARMFUL CODE.  LICENSEE ASSUMES THE ENTIRE
* RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR ASSOCIATED MATERIALS,
* AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION GENERATED USING
* SOFTWARE.
*/

/**
* @version $Revision: 1.30 $ $Author: srikrish $ $Date: 2004/09/09 06:55:32 $ (GMT)
* @author Sriram Krishnan [mailto:srikrish@extreme.indiana.edu]
*/

package xcat.mobile.coordinator;

import gov.cca.TypeMap;

import intf.ccacore.XCATConnectionID;
import intf.ccacore.XCATConnectionInfo;
import intf.services.XCATBuilderService;
import intf.mobile.ccacore.MobileComponentID;
import intf.mobile.coordinator.AppCoordinator;
import intf.mobile.coordinator.AppCoordinatorCallback;
import intf.mobile.coordinator.ComponentInfo;
import intf.mobile.storage.MasterStorageService;
import intf.mobile.storage.IndividualStorageService;

import xcat.ports.BasicPortImpl;
import xcat.ccacore.XCATConnectionIDImpl;
import xcat.services.XCATBuilderServiceImpl;
import xcat.mobile.ccacore.MobileComponentIDClientImpl;
import xcat.exceptions.NonstandardException;
import xcat.util.HandleResolver;
import xcat.util.URLToReference;
import xcat.types.TypeMapImpl;
import xcat.schema.ComponentStaticInformation;
import xcat.schema.ExecutionEnv;
import xcat.schema.NameValuePair;

import soaprmi.util.logging.Logger;
import soaprmi.server.UnicastRemoteObject;
import soaprmi.soaprpc.SoapServices;

import org.exolab.castor.xml.Unmarshaller;

import java.util.Hashtable;
import java.util.Vector;
import java.io.StringReader;

import com.mysql.jdbc.Driver;
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.PreparedStatement;

/**
* The Application Coordinator which is responsible for checkpointing and
* migration of an application (which is a set of components)
*/
public class AppCoordinatorImpl extends BasicPortImpl
  implements AppCoordinator {

  private static Logger logger = Logger.getLogger();

  // map of component names and componentInfos
  private Hashtable componentMap;

  // map of component names and handles
  private Hashtable instanceMap;

  // connection graph for the components
  private Hashtable connectionMap;

  // a map for consistent checkpoints
  private Hashtable checkpointMap;

  // a map for intermediate checkpoints
  private Hashtable tempCheckpointMap;

  // a map for storing component migration status
  private Hashtable migrationMap;

  // number of components frozen not accounted for - needed for distributed checkpointing
  private int outstandingFrozenComps;

  // number of components who have stored their states already
  private int numComponentsStateStored;

  // the status of distributed checkpoint
  private int checkpointStatus;

  // the name of the application coordinator instance
  private String applicationName;

  // the unique ID for this application
  private String applicationID;

  // database parameters
  String dburl;
  String dbuser;
  String dbpasswd;
  boolean cInfoStored;

  /**
   * Default constructor
   * @param applicationName_ the name of this application (coordinator)
   * @param applicationID_ the unique ID for this application
   */
  public AppCoordinatorImpl(String applicationName_,
          String applicationID_)
    throws Exception {
    this(applicationName_, applicationID_, null, null, null);
  }

  /**
   * Constructor
   * @param applicationName_ the name of this application (coordinator)
   * @param applicationID_ the unique ID for this application
   * @param dburl_ the URL for the database to store the state
   * @param dbuser_ the username to use while connecting to the database
   * @param dbpasswd_ the password for the above user
   */
  public AppCoordinatorImpl(String applicationName_,
          String applicationID_,
          String dburl_,
          String dbuser_,
          String dbpasswd_)
    throws Exception {
    applicationName = applicationName_;
    applicationID = applicationID_;
    dburl = dburl_;
    dbuser = dbuser_;
    dbpasswd = dbpasswd_;
    cInfoStored = false;

    // initialize the maps
    componentMap = new Hashtable();
    instanceMap = new Hashtable();
    connectionMap = new Hashtable();
    checkpointMap = new Hashtable();
    tempCheckpointMap = new Hashtable();
    migrationMap = new Hashtable();

    // export the AppCoordinator as a Grid service
    logger.finest("exporting AppCoordinator as a Grid service");
    UnicastRemoteObject.exportObject(this,
             new Class[]{AppCoordinatorCallback.class});

    // set the outstanding number of components frozen to zero
    outstandingFrozenComps = 0;

    // set the number of components who have stored their states to zero
    numComponentsStateStored = 0;

    // set the checkpoint status
    checkpointStatus = AppCoordinatorCallback.READY;

    // load the MySQL database driver
    new Driver();
  }

  //----------------------------------------------------------------//
  // List of methods added to create the component connection graph //
  //----------------------------------------------------------------//

  /**
   * Loads the state of the Application Coordinator from a database
   */
  public void loadFromDatabase()
    throws gov.cca.CCAException {
    // make sure the database URL is not null
    if (dburl == null)
      throw new NonstandardException("Database URL is Null");

    // connection information is already in database
    cInfoStored = true;

    try {
      Connection conn = null;
      // connect to the database
      conn = DriverManager.getConnection(dburl,
           dbuser,
           dbpasswd);
     
     
      // get the list of components for this application
      String sqlStmt0 =
  "select * from coordinator_table where " +
  "application_id = '" + applicationID + "';";
      PreparedStatement stmt0 = conn.prepareStatement(sqlStmt0);
      ResultSet rs0 = stmt0.executeQuery();

      // convert the result set into ComponentInfo[]'s
      rs0.last();
      ComponentInfo[] cInfo = new ComponentInfo[rs0.getRow()];
      rs0.beforeFirst();
      int i = 0;
      while (rs0.next()) {
  cInfo[i++] = new ComponentInfoImpl(rs0.getString("instance_name"),
             rs0.getString("instance_handle"),
             rs0.getString("instance_location"),
             rs0.getString("creation_proto"),
             rs0.getString("component_xml"));
      }

      // create a connection graph from retrieved information
      createConnectionGraph(cInfo);

      // load information about old checkpoints
      String sqlStmt1 =
  "select * from distributed_checkpoint_table where " +
  "application_id = '" + applicationID + "';";
      PreparedStatement stmt1 = conn.prepareStatement(sqlStmt1);
      ResultSet rs1 = stmt1.executeQuery();

      // convert the result set into ComponentInfo[]'s
      rs1.beforeFirst();
      while (rs1.next()) {
  CheckpointInfo cpInfo =
    new CheckpointInfo(rs1.getString("individual_storage_service_url"),
           rs1.getString("storage_id"));
  String instanceName =
    (String) instanceMap.get(rs1.getString("instance_handle"));
  checkpointMap.put(instanceName, cpInfo);
      }

      // clean up
      conn.close();
    } catch (Exception e) {
      logger.severe("Error while loading AppCoordinator state from database", e);
      throw new NonstandardException("Error while loading AppCoordinator state from database",
             e);
    }
  }

  /**
   * Set up the connection graph using an array of ComponentInfo
   * @param componentInfo an array of ComponentInfo objects
   */
  public void createConnectionGraph(ComponentInfo[] componentInfo)
    throws gov.cca.CCAException {

    // set up the nodes
    for (int i = 0; i < componentInfo.length; i++) {
      addNode(componentInfo[i].getInstanceName(),
        componentInfo[i]);
    }

    // set up the edges
    for (int i = 0; i < componentInfo.length; i++) {
      String usesComponentName = componentInfo[i].getInstanceName();
      MobileComponentID cid =
  new MobileComponentIDClientImpl(usesComponentName,
          componentInfo[i].getInstanceHandle());
      String[] usesPortNames = cid.getUsedPortNames();

      // Add an edge for every uses port
      for (int j = 0; j < usesPortNames.length; j++) {
  logger.finest("Adding a connection for" +
          " uses component: " +
          usesComponentName +
          ", uses port: " +
          usesPortNames[j]);

  // Get the ConnectionID for this uses port
  XCATConnectionInfo connInfo = cid.getConnectionInfo(usesPortNames[j]);

  // If this port is not connected, skip to next iteration
  if (connInfo == null)
    continue;

  // Add this edge physically
  addEdge(connInfo.getUserName(),
    connInfo.getUserIDHandle(),
    connInfo.getUserPortName(),
    connInfo.getProviderName(),
    connInfo.getProviderIDHandle(),
    connInfo.getProviderPortName());
      }
    }

    // make sure a database url is provided, and this is already not done
    if ((dburl == null) || cInfoStored)
      return;
    // Commit component information into database
    Connection conn = null;
    try {
      // connect to the database
      conn = DriverManager.getConnection(dburl,
           dbuser,
           dbpasswd);
     
      // set autocommit to false so that all of the following is atomic
      conn.setAutoCommit(false);
    } catch (Exception e) {
      logger.severe("Error while connecting to database", e);
      throw new NonstandardException("Error while connecting to database", e);
    }

    try {
      // for every ComponentInfo, add one insert statement
      for (int i = 0; i < componentInfo.length; i++) {
  String sqlStmt =
    "insert into coordinator_table(instance_name, " +
    "instance_location, creation_proto, component_xml, " +
    "instance_handle, application_id) values (" +
    "'" + componentInfo[i].getInstanceName() + "', " +
    "'" + componentInfo[i].getInstanceLocation() + "', " +
    "'" + componentInfo[i].getCreationProto() + "', " +
    "'" + componentInfo[i].getComponentXML() + "', " +
    "'" + componentInfo[i].getInstanceHandle() + "', " +
    "'" + applicationID + "');";
  PreparedStatement stmt = conn.prepareStatement(sqlStmt);
  stmt.executeUpdate();
      }
     
      // add a single entry into the application map table
      String sqlStmt =
  "insert into app_map_table(application_id, application_name) values " +
  "('" + applicationID + "', '" + applicationName + "');";
      PreparedStatement stmt = conn.prepareStatement(sqlStmt);
      stmt.executeUpdate();

      // commit all inserts
      conn.commit();

      // clean up
      conn.close();
    } catch (Exception e) {
      logger.severe("Error while trying to store state into database: " +
        " Trying to rollback", e);
     
      // try to rollback
      try {
  conn.rollback();
      } catch (Exception re) {
  logger.severe("Error while trying to store state into database: " +
          " Rollback failed", re);
  throw new NonstandardException("Error while trying to store state into database: " +
               " Rollback failed", re);
      }

      throw new NonstandardException("Error while trying to store state into database: " +
             " Rollback successful", e);
    }
  }

  /**
   * Add a component instance to the component graph
   * @param componentName the instanceName for the component
   * @param componentInfo the information for this component
   */
  private void addNode(String componentName,
           ComponentInfo componentInfo)
    throws gov.cca.CCAException {
    logger.finest("called with component name: " + componentName);

    if (componentMap.containsKey(componentName))
      throw new NonstandardException("Component " + componentName +
             " already exists");

    // add the ComponentInfo for this component
    componentMap.put(componentName, componentInfo);

    // add a mapping from instanceHandle to componentName
    instanceMap.put(componentInfo.getInstanceHandle(), componentName);
  }

  /**
   * Add an edge to the component graph
   * @param usesComponentName the instanceName for the uses side of the connection
   * @param usesComponentHandle the GSH of the uses component
   * @param usesPortName the name of the uses port
   * @param providesComponentName the instanceName for the provides side
   * @param providesComponentHandle the GSH of the provides component
   * @param providesPortName the name of the provides port
   */
  private void addEdge(String usesComponentName,
           String usesComponentHandle,
           String usesPortName,
           String providesComponentName,
           String providesComponentHandle,
           String providesPortName)
    throws gov.cca.CCAException {
    logger.finest("called with uses component: " + usesComponentName +
      " and provides component: " + providesComponentName);

    if (!componentMap.containsKey(usesComponentName))
      throw new NonstandardException("Component " + usesComponentName +
             " not present in the graph");
    if (!componentMap.containsKey(providesComponentName))
      throw new NonstandardException("Component " + providesComponentName +
             " not present in the graph");

    // retrieve componentIDs for the uses and provides side
    MobileComponentID userID =
      new MobileComponentIDClientImpl(usesComponentName,
              usesComponentHandle);
    MobileComponentID providerID =
      new MobileComponentIDClientImpl(providesComponentName,
              providesComponentHandle);
   
    // create a ConnectionID for this connection
    XCATConnectionID connID =
      new XCATConnectionIDImpl(providerID,
             userID,
             providesPortName,
             usesPortName,
             providesComponentHandle);

    // add this connectionID for the provides side
    if (connectionMap.containsKey(providesComponentName)) {
      Vector connIDs = (Vector) connectionMap.get(providesComponentName);
      connIDs.add(connID);
    } else {
      Vector connIDs = new Vector();
      connIDs.add(connID);
      connectionMap.put(providesComponentName, connIDs);
    }
  }
 
  //------------------------------------------------------//
  //     List of methods added to support migration       //
  //------------------------------------------------------//

  /**
   * A request to migrate a component, which might be triggered by several reasons
   * @param componentName the instance name of the component requesting migration
   * @param targetLocation the location that the component should migrate to
   * @param masterStorageServiceURL the URL of the Master Storage Service
   */
  public void migrateComponent(String componentName,
             String targetLocation,
             String masterStorageServiceURL)
    throws gov.cca.CCAException {

    // Retrieve information for this component
    if (!componentMap.containsKey(componentName))
      throw new NonstandardException("Unknown component: " + componentName);
    ComponentInfo cInfo = (ComponentInfo) componentMap.get(componentName);
   
    // create empty connection list if entry for this component doesn't exist
    if (!connectionMap.containsKey(componentName)) {
      Vector connIDs = new Vector();
      connectionMap.put(componentName, connIDs);
    }

    // Get a list of connections for this component
    Vector connIDs = (Vector) connectionMap.get(componentName);
   
    // Send migration requests to all connected components
    int numConns = connIDs.size();
    logger.finest("found " + numConns + " connection " +
      "for component " + componentName);
   
    // create an entry into the migrationMap
    MigrationInfo mInfo = new MigrationInfo(numConns);
    migrationMap.put(componentName, mInfo);
   
    for (int i = 0; i < numConns; i++) {
      XCATConnectionID connID = (XCATConnectionID) connIDs.get(i);
      MobileComponentID userID = (MobileComponentID) connID.getUser();
     
      userID.requestMigration(componentName,
            connID.getUserPortName(),
            getGSH());
    }
   
    // Wait till all users are OK with migration
    synchronized(mInfo) {
      if (mInfo.getApprovedUsers() < numConns) {
  try {
    mInfo.wait();
  } catch (InterruptedException ie) {
    logger.severe("Exception when waiting for uses sides to approve migration",
      ie);
    throw new NonstandardException("Exception when waiting for migration approval",
           ie);
  }
      }
    }

    // check if the above call was successful
    if (mInfo.getMigrationStatus() == AppCoordinatorCallback.EXCEPTION)
      throw new NonstandardException("Remote side did not approve migration");

    // Confirm to all users that provider is migrating
    for (int i = 0; i < numConns; i++) {
      XCATConnectionID connID = (XCATConnectionID) connIDs.get(i);
      MobileComponentID userID = (MobileComponentID) connID.getUser();
      userID.confirmMigration(connID.getUserPortName());
    }
   
    // Freeze the execution of the component
    MobileComponentID cid =
      new MobileComponentIDClientImpl(cInfo.getInstanceName(),
              cInfo.getInstanceHandle());
    cid.freezeComponent(getGSH());
   
    // Wait till the component sends back a notification that it is frozen
    synchronized(mInfo) {
      if (!mInfo.getIsFrozen()) {
  try {
    mInfo.wait();
  } catch (InterruptedException ie) {
    logger.severe("Exception when waiting for migration to complete",
      ie);
    throw new NonstandardException("Exception when waiting for migration to complete",
           ie);
  }
      }
    }
   
    // decrement number of outstanding frozen components
    synchronized(this) {
      outstandingFrozenComps--;
    }

    // check if the above call was successful
    if (mInfo.getMigrationStatus() == AppCoordinatorCallback.EXCEPTION)
      throw new NonstandardException("Remote component threw exception while being frozen");

    // Store the individual component state into persistent storage
    MasterStorageService mss = (MasterStorageService)
      URLToReference.createReference(masterStorageServiceURL,
             MasterStorageService.class.getName());
    String individualStorageServiceURL = mss.getIndividualStorageServiceLocation();
    String storageID = cid.storeIndividualComponentState(individualStorageServiceURL);

    // destroy the remote component
    try {
      cid.destroy();
    } catch (Exception e) {
      logger.severe("Caught exception while trying to destroy component",
        e);
      throw new NonstandardException("Caught exception while trying to destroy component",
             e);
    }

    // create a new instance of the component at the specified location
    cInfo.setInstanceLocation(targetLocation);
    createComponentInstance(cInfo);

    // retrieve the state for the migrated component
    cid.loadComponentState(individualStorageServiceURL, storageID);

    // delete state from storage service
    IndividualStorageService iss = (IndividualStorageService)
      URLToReference.createReference(individualStorageServiceURL,
             IndividualStorageService.class.getName());
    iss.deleteState(storageID);

    // resume execution of the migrated component
    cid.resumeExecution();

    // set the isFrozen false to false
    mInfo.setIsFrozen(false);

    // send a notification that all connected components that migration is complete
    for (int i = 0; i < numConns; i++) {
      XCATConnectionID connID = (XCATConnectionID) connIDs.get(i);
      MobileComponentID userID = (MobileComponentID) connID.getUser();
      userID.migrationComplete(connID.getUserPortName());     
    }

    // get rid of the entry inside migrationMap
    migrationMap.remove(componentName);
  }

  /**
   * Creates an instance of the component from the ComponentInfo object
   * @param cInfo the ComponentInfo object for the component needing instantiation
   */
  private void createComponentInstance(ComponentInfo cInfo)
    throws gov.cca.CCAException {

    // create a new instance of the component
    ExecutionEnv[] executionEnvList = null;
    try {
      // parse the xml description of the component
      StringReader readerCompStaticInfo = new StringReader(cInfo.getComponentXML());
      ComponentStaticInformation compStaticInfo  =
        (ComponentStaticInformation)Unmarshaller.unmarshal
        (ComponentStaticInformation.class, readerCompStaticInfo);
      executionEnvList = compStaticInfo.getExecutionEnv();
    } catch (Exception e) {
      logger.severe("Exception thrown while parsing Component XML", e);
      throw new NonstandardException("Exception while parsing Component XML", e);
    }

    // create a new TypeMap and fill in the values
    TypeMap componentEnv = new TypeMapImpl();
    componentEnv.putString("execHost", cInfo.getInstanceLocation());
    componentEnv.putString("creationProto", cInfo.getCreationProto());

    // check if a valid installation exists for this host/proto
    boolean found = false;
    for (int k = 0; k < executionEnvList.length; k++) {
      ExecutionEnv executionEnv = executionEnvList[k];
      String[] hostName = executionEnv.getHostName();
      String[] creationMech = executionEnv.getCreationProto();

      // check if there is a match for the hostName
      int h;
      for (h = 0; h < hostName.length; h++) {
  if (hostName[h].equals(cInfo.getInstanceLocation())) {
    break;
  }
      }

      // if h equals hostName.length, then skip
      if (h == hostName.length)
  continue;
     
      // check if there is a match for creationProto
      int m;
      for (m = 0; m < creationMech.length; m++) {
  if (creationMech[m].equals(cInfo.getCreationProto())) {
    break;
  }
      }

      // if h equals creationMech.length, then skip
      if (m == creationMech.length)
  continue;
     
      // if we get here, this is a valid installation for this
      // creationProto/execHost pair
      NameValuePair[] nameValuePairList =
  executionEnv.getNameValuePair();
      for (int l = 0; l < nameValuePairList.length; l++) {
  NameValuePair nameValuePair = nameValuePairList[l];
  String nameOfVariable = nameValuePair.getName();
  String value = nameValuePair.getValue();
  componentEnv.putString(nameOfVariable, value);
      }
     
      // found an installation, break here
      found = true;
      break;
    }
   
    // if no valid installation found, throw an Exception
    if (!found) {
      String message = new String ("No valid installation for : " +
           cInfo.getInstanceLocation() + " , " +
           cInfo.getCreationProto());
      logger.severe(message);
      throw new NonstandardException(message);
    }

    // get the name of the class for the component
    String className = componentEnv.getString("className",
               "None");
    if (className.equals("None"))
      throw new NonstandardException("Property className for component not defined");
   
    // notify that this is a migration
    componentEnv.putString("componentHandle", cInfo.getInstanceHandle());
    componentEnv.putBool("isMigrated", true);

    // invoke the Builder Service to create a new instance
    XCATBuilderService builderService = null;
    try {
      builderService = new XCATBuilderServiceImpl(false);
    } catch (Exception e) {
      logger.severe("Can't instantiate Builder service", e);
      throw new NonstandardException("Can't instantiate Builder service", e);
    }
    String builderGSH = HandleResolver.createGSH("coordinatorbuilderService");
    builderService.setGSH(builderGSH);
    HandleResolver.addReference(builderGSH, builderService);
    builderService.createInstance(cInfo.getInstanceName(),
          className,
          componentEnv);

  }

  //--------------------------------------------------------//
  //  List of methods added for distributed checkpointing   //
  //--------------------------------------------------------//

  /**
   * A request to the AppCoordinator to checkpoint all components
   * @param masterStorageServiceURL the URL of the Master Storage Service
   */
  public void checkpointComponents(String masterStorageServiceURL)
    throws gov.cca.CCAException {
    logger.finest("called");

    // send a request to freeze execution of all components
    long time0 = System.currentTimeMillis();
    Object[] componentList = componentMap.values().toArray();
    for (int i = 0; i < componentList.length; i++) {
      ComponentInfo cInfo = (ComponentInfo) componentList[i];
      MobileComponentID cid =
  new MobileComponentIDClientImpl(cInfo.getInstanceName(),
          cInfo.getInstanceHandle());
      cid.freezeComponent(getGSH());
    }
    long time1 = System.currentTimeMillis();
    logger.info("Freeze request: " + (time1 - time0));

    // wait till all components are frozen
    if (outstandingFrozenComps < componentList.length) {
      synchronized(this) {
  try {
    wait();
  } catch (InterruptedException ie) {
    logger.severe("Exception when waiting for component to be frozen",
      ie);
    throw new NonstandardException("Exception when waiting for component to be frozen",
           ie);
  }

  // set the number of outstanding frozen components to 0
  outstandingFrozenComps = 0;

  // check if the above call was successful
  if (checkpointStatus == AppCoordinatorCallback.EXCEPTION)
    throw new NonstandardException("Exception while freezing components");
      }
    }
    long time2 = System.currentTimeMillis();
    logger.info("Time for components to freeze: " + (time2 - time1));

    // send request to store the state of the components
    MasterStorageService mss = (MasterStorageService)
      URLToReference.createReference(masterStorageServiceURL,
             MasterStorageService.class.getName());
    for (int i = 0; i < componentList.length; i++) {
      String individualStorageServiceURL = mss.getIndividualStorageServiceLocation();
      ComponentInfo cInfo = (ComponentInfo) componentList[i];
      MobileComponentID cid =
  new MobileComponentIDClientImpl(cInfo.getInstanceName(),
          cInfo.getInstanceHandle());
      cid.appendStateToCheckpoint(individualStorageServiceURL, getGSH());
    }

    // wait till all components have stored their states
    if (numComponentsStateStored < componentList.length) {
      synchronized(this) {
  try {
    wait();
  } catch (InterruptedException ie) {
    logger.severe("Exception when waiting for components to store states",
      ie);
    throw new NonstandardException("Exception when waiting for components to store states",
           ie);
  }

  // set the number of outstanding frozen components to 0
  numComponentsStateStored = 0;

  // check if the above call was successful
  if (checkpointStatus == AppCoordinatorCallback.EXCEPTION)
    throw new NonstandardException("Exception while storing component state");
      }
    }
    long time3 = System.currentTimeMillis();
    logger.info("Storing checkpoints: " + (time3 - time2));

    // Atomically update locations of checkpoints in the database
    Hashtable oldCheckpointMap = checkpointMap;
    checkpointMap = tempCheckpointMap;
    tempCheckpointMap = new Hashtable();
    if (dburl != null) {
      // Commit component information into database
      Connection conn = null;
      try {
  // connect to the database
  conn = DriverManager.getConnection(dburl,
             dbuser,
             dbpasswd);
 
  // set autocommit to false so that all of the following is atomic
  conn.setAutoCommit(false);
      } catch (Exception e) {
  logger.severe("Error while connecting to database", e);
  throw new NonstandardException("Error while connecting to database", e);
      }

      try {
  // for every component, update the distributed_checkpoint_table
  for (int i = 0; i < componentList.length; i++) {
    ComponentInfo cInfo = (ComponentInfo) componentList[i];
    CheckpointInfo cpInfo =
      (CheckpointInfo) checkpointMap.get(cInfo.getInstanceName());

    // update the entry into the table
    // have to delete + insert since MySQL 4.0.x doesn't support
    // ON DUPLICATE KEY UPDATE
    String sqlStmt0 =
      "delete from distributed_checkpoint_table where " +
      "instance_handle = '" +  cInfo.getInstanceHandle() + "';";
    PreparedStatement stmt0 = conn.prepareStatement(sqlStmt0);
    stmt0.executeUpdate();

    String sqlStmt1 =
      "insert into distributed_checkpoint_table" +
      "(instance_handle, application_id, " +
      "individual_storage_service_url, " +
      "storage_id) values (" +
      "'" + cInfo.getInstanceHandle() + "', " +
      "'" + applicationID + "', " +
      "'" + cpInfo.getStorageServiceURL() + "', " +
      "'" + cpInfo.getStorageID() + "');";
    PreparedStatement stmt1 = conn.prepareStatement(sqlStmt1);
    stmt1.executeUpdate();
  }
   
  // commit all inserts
  conn.commit();
 
  // clean up
  conn.close();
      } catch (Exception e) {
  logger.severe("Error while trying to store checkpoint locations into database: " +
          " Trying to rollback", e);
 
  // try to rollback
  try {
    conn.rollback();
  } catch (Exception re) {
    logger.severe("Error while trying to store checkpoint locations into database: " +
      " Rollback failed", re);
    throw new NonstandardException("Error while trying to store checkpoint locations " +
           "into database: Rollback failed", re);
  }
 
  throw new NonstandardException("Error while trying to store checkpoint locations " +
               "into database: Rollback successful", e);
      }
    }

    // delete old checkpoints
    Object[] cpList = oldCheckpointMap.values().toArray();
    for (int i = 0; i < cpList.length; i++) {
      CheckpointInfo cpInfo = (CheckpointInfo) cpList[i];
      IndividualStorageService iss = (IndividualStorageService)
  URLToReference.createReference(cpInfo.getStorageServiceURL(),
               IndividualStorageService.class.getName());
      iss.deleteState(cpInfo.getStorageID());
    }

    long time4 = System.currentTimeMillis();
    logger.info("Committing checkpoints: " + (time4 - time3));

    // send a notification to components that checkpointing is complete
    for (int i = 0; i < componentList.length; i++) {
      ComponentInfo cInfo = (ComponentInfo) componentList[i];
      MobileComponentID cid =
  new MobileComponentIDClientImpl(cInfo.getInstanceName(),
          cInfo.getInstanceHandle());
      cid.unfreezeComponent();
    }
    long time5 = System.currentTimeMillis();
    logger.info("Unfreezing components: " + (time5 - time4));
  }

  /**
   * A request to the AppCoordinator to restart from latest checkpoint
   */
  public void restartFromCheckpoint()
    throws gov.cca.CCAException {

    // destroy all the components, if they are still alive
    Object[] componentList = componentMap.values().toArray();
    for (int i = 0; i < componentList.length; i++) {
      ComponentInfo cInfo = (ComponentInfo) componentList[i];
      MobileComponentID cid =
  new MobileComponentIDClientImpl(cInfo.getInstanceName(),
          cInfo.getInstanceHandle());
      try {
  cid.destroy();
      } catch (Exception e) {
  logger.severe("Caught exception while trying to destroy component",
          e);
  // continue since the component may be dead already
      }
    }

    // instantiate all components again
    for (int i = 0; i < componentList.length; i++) {
      ComponentInfo cInfo = (ComponentInfo) componentList[i];
      createComponentInstance(cInfo);
    }

    // load the checkpointed state
    for (int i = 0; i < componentList.length; i++) {
      ComponentInfo cInfo = (ComponentInfo) componentList[i];
      CheckpointInfo cpInfo = (CheckpointInfo) checkpointMap.get(cInfo.getInstanceName());

      MobileComponentID cid =
  new MobileComponentIDClientImpl(cInfo.getInstanceName(),
          cInfo.getInstanceHandle());
      cid.loadComponentState(cpInfo.getStorageServiceURL(),
           cpInfo.getStorageID());
    }

    // tell all components to proceed
    for (int i = 0; i < componentList.length; i++) {
      ComponentInfo cInfo = (ComponentInfo) componentList[i];
      MobileComponentID cid =
  new MobileComponentIDClientImpl(cInfo.getInstanceName(),
          cInfo.getInstanceHandle());
      cid.resumeExecution();
    }
  }

  //----------------------------------------------------//
  //   List of callback methods for the AppCoordinator  //
  //----------------------------------------------------//

  /**
   * A notification that this component has been frozen
   * @param componentName the instance name of the component undergoing migration
   * @param status        Possible values: AppCoordinatorCallback.FROZEN,
   *                                       AppCoordinatorCallback.EXCEPTION
   */
  public void componentFrozen(String componentName,
            int status)
    throws gov.cca.CCAException {
    logger.finest("called for component: " + componentName);

    if (!componentMap.containsKey(componentName))
      throw new NonstandardException("Unknown component: " + componentName);

    synchronized(this) {
      // increment the number of outstanding components frozen
      outstandingFrozenComps++;

      // if this is an exception, set the appropriate flag
      if (status == AppCoordinatorCallback.EXCEPTION)
  checkpointStatus = status;

      // wake up sleeping thread if all components have been frozen
      if (outstandingFrozenComps == componentMap.size())
  notify();
    }

    // the following is executed only during migration
    MigrationInfo mInfo =
      (MigrationInfo) migrationMap.get(componentName);
    if (mInfo != null) {
      synchronized(mInfo) {     
  // set a flag to signify that component has been frozen
  mInfo.setIsFrozen(true);

  // if this is an exception, set the appropriate flag
  if (status == AppCoordinatorCallback.EXCEPTION)
    mInfo.setMigrationStatus(status);

  // wake up thread which is sleeping for migration to complete
  mInfo.notify();
      }
    }
  }

  /**
   * A notification that the component has stored its state
   * @param componentName the instance name of the component undergoing migration
   * @param storageServiceURL the URL of the Individual Storage Service used
   * @param storageID the storageID returned by the Individual Storage Service
   * @param status        Possible values: AppCoordinatorCallback.FROZEN,
   *                                       AppCoordinatorCallback.EXCEPTION
   */
  public void componentCheckpointed(String componentName,
            String storageServiceURL,
            String storageID,
            int status)
    throws gov.cca.CCAException {
    logger.finest("called for component: " + componentName);

    if (!componentMap.containsKey(componentName))
      throw new NonstandardException("Unknown component: " + componentName);

    // add checkpoint information inside the checkpointMap
    CheckpointInfo cpInfo = new CheckpointInfo(storageServiceURL,
                 storageID);
    tempCheckpointMap.put(componentName, cpInfo);

    synchronized(this) {
      // increment the number of components who have stored their state
      numComponentsStateStored++;

      // if this is an exception, set the appropriate flag
      if (status == AppCoordinatorCallback.EXCEPTION)
  checkpointStatus = status;

      // wake up sleeping thread if all components have been frozen
      if (numComponentsStateStored == componentMap.size())
  notify();
    }
  }

  /**
   * A notification that the component using this uses port is
   * ready for migration of the provides side
   * @param providesComponentName the name of the provides side requesting migration
   * @param componentName the instance name for component with the uses port
   * @param usingPortName the name of the uses port that is connected to
   *                      the component undergoing migration
   * @param status Possible values: AppCoordinor.READY, AppCoordinator.EXCEPTION
   */
  public void migrationApproval(String providesComponentName,
        String componentName,
        String usingPortName,
        int status)
    throws gov.cca.CCAException {
    logger.finest("called by component : " + componentName +
      " for uses port: " + usingPortName +
      " with status: " + status +
      " for component: " + providesComponentName);

    if (!componentMap.containsKey(providesComponentName) ||
  !migrationMap.containsKey(providesComponentName))
      throw new NonstandardException("Unknown component: " + providesComponentName);

    MigrationInfo mInfo =
      (MigrationInfo) migrationMap.get(providesComponentName);
    synchronized(mInfo) {
     
      // increment the number of users who approve this migration
      mInfo.incrApprovedUsers();

      // if this is an exception message, set it inside mStatus
      if (status == AppCoordinatorCallback.EXCEPTION)
  mInfo.setMigrationStatus(status);

      // notify sleeping thread if all uses sides have approved migration
      if (mInfo.getApprovedUsers() == mInfo.getNumUsers())
  mInfo.notify();
    }
  }
}
TOP

Related Classes of xcat.mobile.coordinator.AppCoordinatorImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.