Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Little correction on crash detection.
[hpcvm.git] / src / and / hpcvm / Server.java
index 0c696a4..7c31580 100644 (file)
@@ -11,6 +11,7 @@ import java.rmi.registry.Registry;
 import java.rmi.server.UnicastRemoteObject;
 import java.util.ArrayList;
 import java.util.Iterator;
+import java.util.concurrent.Semaphore;
 
 
 public class Server extends UnicastRemoteObject implements ServicesServer
@@ -31,119 +32,7 @@ public class Server extends UnicastRemoteObject implements ServicesServer
                }
                
                protected int getNb() { return nb ; }
-       }
-       
-       
-       private class ConnectedClient
-       {
-               private ServicesClient stub ;
-               private int timeout ;
-               private Status state ;
-               private String ip ;
-               private String name ;
-               private ComputingClient cl ;
-               
-               ConnectedClient( ServicesClient _stub )
-               {
-                       stub = _stub ;
-                       timeout = 0 ;
-                       state = new Status() ;
-                       state.setStatus( "connected" ) ;
-                       try {
-                               ip = stub.getIPHost() ;
-                               name = stub.getName() ;
-                       } catch (RemoteException e) {
-                               e.printStackTrace();
-                       }
-                       cl = null ;
-               }
-               
-               protected ServicesClient getStub() { return stub ; }
-               
-               protected void setStub( ServicesClient _stub ) { stub = _stub ; }
-               
-               protected int getTimeout() { return timeout ; }
-               
-               protected void incTimeout() { timeout++ ; }
-               
-               protected void resetTimeout() { timeout = 0 ; }
-               
-               protected String getStatus() { return state.getStatus() ; }
-               
-               protected void setStatus( String _state ) { state.setStatus( _state ) ; }
-               
-               protected String getIP() { return ip ; }
-               
-               protected String getName() { return name ; } ;
-               
-               protected void setComputingClient( ComputingClient _cl ) { cl = _cl ; }
-               
-               protected ComputingClient getComputingClient() { return cl ; } 
-       }
-       
-       
-       private class ComputingClient
-       {
-               private ConnectedClient client ;
-               private boolean save_status ;
-               private ArrayList<ServicesClient> save_neighbor ;
-               private String lastSaveName ;
-               
-               ComputingClient( ConnectedClient cl )
-               {
-                       client = cl ;
-                       save_status = false ;
-                       save_neighbor = new ArrayList<ServicesClient>() ;
-                       lastSaveName = "none" ;
-               }
-               
-               protected ConnectedClient getClient() { return client ; }
-               
-               protected boolean getSaveStatus(){ return save_status ; }
-               
-               protected void setSaveStatus( boolean _status ) { save_status = _status ; }
-               
-               protected void setSaveNeighbor( ServicesClient _sn ) 
-               { 
-                       if( _sn != null )
-                       {
-                               if( save_neighbor.size() == 0 )
-                               {
-                                       save_neighbor.add( _sn ) ;
-                               } else {
-                                       save_neighbor.set( 0, _sn ) ;
-                               }
-                               
-//                             System.out.println( "My save neighbor is " + _sn ) ;
-                       
-                               try {
-                                       client.getStub().setSavingNeighbor( _sn ) ;
-                               } catch( RemoteException e ) {
-                                       System.err.println( "Error while setting save neighbor on " + 
-                                                       client.getName() + "(" + client.getIP() + ")!" ) ;
-                                       e.printStackTrace() ;
-                               }
-                       }
-               }
-               
-               protected ServicesClient getSaveNeighbor() 
-               {
-                       if( save_neighbor.isEmpty() )
-                       {
-                               return null ;
-                       } else {
-                               return save_neighbor.get( 0 ) ;
-                       }
-               }
-
-               public void setLastSave( String _saveName ) 
-               {
-                       lastSaveName = _saveName ;                      
-               }
-               
-               public String getLastSave() { return lastSaveName ; }
-               
-       }
+       }       
        
        
        private class IPAssociation
@@ -153,8 +42,8 @@ public class Server extends UnicastRemoteObject implements ServicesServer
                
                IPAssociation()
                {
-                       vmIP = null ;
-                       hostIP = null ;
+                       vmIP = "" ;
+                       hostIP = "" ;
                }
                
                protected void setVmIP( String _vmIP )
@@ -184,11 +73,20 @@ public class Server extends UnicastRemoteObject implements ServicesServer
        private int port ;
        private ArrayList<ConnectedClient> clients ;
        private ArrayList<ComputingClient> computingClients ;
+       private ArrayList<RunningApplication> applications ;
        private int max_timeout ;
        private ConnectedMonitor monitor ;
        private DiscCount counter ;
        private ArrayList<IPAssociation> vmIPs ;
        private String working_directory ;
+       private long save_interleave ;
+       private Semaphore semaSave ;
+       private OperatingClients startingClients ;
+       private OperatingClients deployingClients ;
+       private LimitThread limitThread ;
+       private int maxThread ;
+       private int ind ;
+       private boolean running ;
        
        
        protected Server() throws RemoteException 
@@ -203,49 +101,52 @@ public class Server extends UnicastRemoteObject implements ServicesServer
        {
                if( _stub != null )
                {
-                       String ip = "" ;
-                       try {
-                               ip = _stub.getIPHost() ;
-                       } catch (RemoteException e) {
-                               e.printStackTrace() ;
-                               return 1 ;
-                       }
-                       
-                       boolean exists = false ;
-                       int i ;
-                       
-                       for( i = 0 ; i < clients.size() ; i++ )
+                       synchronized( clients )
                        {
-                               if( ip.equals( clients.get( i ).getIP() ) )
+                               String ip = "" ;
+                               try {
+                                       ip = _stub.getIPHost() ;
+                               } catch (RemoteException e) {
+                                       e.printStackTrace() ;
+                                       return 1 ;
+                               }
+
+                               boolean exists = false ;
+                               int i ;
+
+                               for( i = 0 ; i < clients.size() ; i++ )
                                {
-                                       exists = true ;
-                                       System.out.println( "Client already connected!" ) ;
-                                       break ;
+                                       if( ip.equals( clients.get( i ).getIP() ) )
+                                       {
+                                               exists = true ;
+                                               System.out.println( "Client already connected!" ) ;
+                                               break ;
+                                       }
                                }
-                       }
-                       
-                       if( exists )
-                       {
-                               System.out.println( "The client stub will be replaced." ) ;
-                               clients.get( i ).setStub( _stub ) ;
-                               System.out.println( "(reconnection of " + clients.get( i ).getName() + ")" ) ;
-                               return 2 ;
-                       } else {
-                               System.out.println( "New connection!" ) ;
-                               clients.add( new ConnectedClient( _stub ) ) ;
-                               System.out.println( "(connection of " + clients.get( clients.size() - 1 ).getName() + ")" ) ;
-                               generateVmIP( ip ) ;
-                               
-                               if( clients.size() == 0 )
+
+                               if( exists )
                                {
-                                       System.out.println( "There is no client connected." ) ;
-                               } else if( clients.size() == 1 ) {
-                                       System.out.println( "There is one client connected." ) ;
+                                       System.out.println( "The client stub will be replaced." ) ;
+                                       clients.get( i ).setStub( _stub ) ;
+                                       System.out.println( "(reconnection of " + clients.get( i ).getName() + ")" ) ;
+                                       return 2 ;
                                } else {
-                                       System.out.println( "There are " + clients.size() + " clients connected." ) ;
-                               }
+                                       System.out.println( "New connection!" ) ;
+                                       clients.add( new ConnectedClient( _stub ) ) ;
+                                       System.out.println( "(connection of " + clients.get( clients.size() - 1 ).getName() + ")" ) ;
+                                       generateVmIP( ip ) ;
+
+                                       if( clients.size() == 0 )
+                                       {
+                                               System.out.println( "There is no client connected." ) ;
+                                       } else if( clients.size() == 1 ) {
+                                               System.out.println( "There is one client connected." ) ;
+                                       } else {
+                                               System.out.println( "There are " + clients.size() + " clients connected." ) ;
+                                       }
 
-                               return 0 ;
+                                       return 0 ;
+                               }
                        }
                }
                
@@ -259,7 +160,7 @@ public class Server extends UnicastRemoteObject implements ServicesServer
                {       
                        for( int i = 0 ; i < vmIPs.size() ; i++ )
                        {
-                               if( vmIPs.get( i ).getHostIP() == null )
+                               if( vmIPs.get( i ).getHostIP().equalsIgnoreCase( "" ) )
                                {
                                        vmIPs.get( i ).setHostIP( _ip ) ;
                                        
@@ -295,9 +196,10 @@ public class Server extends UnicastRemoteObject implements ServicesServer
                        for( int i = 0 ; i < clients.size() ; i++ )
                        {
                                if( _ip.equals( clients.get( i ).getIP() ) ) 
-                               {
+                               {                                       
                                        clients.get( i ).setStatus( _status ) ;
                                        System.out.println( "Client " + clients.get( i ).getName() + " changed its status to: " + _status ) ;
+                                       
                                        break ;
                                }
                        }
@@ -310,12 +212,25 @@ public class Server extends UnicastRemoteObject implements ServicesServer
                port = _port ;
                max_timeout = 4 ;
                
-               clients = new ArrayList<Server.ConnectedClient>() ;
-               computingClients = new ArrayList<Server.ComputingClient>() ;
+               clients = new ArrayList<ConnectedClient>() ;
+               computingClients = new ArrayList<ComputingClient>() ;
+               applications = new ArrayList<RunningApplication>() ;
                monitor = null ;
                
+               startingClients = new OperatingClients() ;
+               deployingClients = new OperatingClients() ;
+               limitThread = new LimitThread() ;
+               maxThread = 20 ;
+               
+               ind = -1 ;
+               running = false ;
+               
                working_directory = "/localhome/vmware" ;
                
+               save_interleave  = 30 * 60 * 1000 ;
+               
+               semaSave = new Semaphore( 1 ) ;
+               
                exportObject() ;
 
                vmIPs = new ArrayList<IPAssociation>() ;
@@ -326,12 +241,15 @@ public class Server extends UnicastRemoteObject implements ServicesServer
                        vmIPs.get( vmIPs.size() - 1 ).setVmIP( "10.11.10." + i ) ;
                }
                
-               clients = new ArrayList<Server.ConnectedClient>() ;
+               clients = new ArrayList<ConnectedClient>() ;
                
                counter = new DiscCount() ;
                
                monitor = new ConnectedMonitor() ;
                monitor.start() ;
+               
+               // TODO
+               // Check if there are running applications ... and restart them :)
        }
        
        
@@ -342,9 +260,11 @@ public class Server extends UnicastRemoteObject implements ServicesServer
                for( int i = 0 ; i < clients.size() ; i++ )
                {
                        try {
+                               clients.get( i ).getStub().emergencyStop() ;
                                clients.get( i ).getStub().stop() ;
                        } catch (RemoteException e) {
-                               e.printStackTrace();
+                               System.err.println( "Unable to send stop signal to " + clients.get( i ).getName() ) ;
+                               e.printStackTrace() ;
                        }
                }
                
@@ -428,6 +348,15 @@ public class Server extends UnicastRemoteObject implements ServicesServer
                                ComputingClient cc = cl.getComputingClient() ;
 //                             ServicesClient dead = cc.getClient().getStub() ;
                                String ipDead = cc.getClient().getIP() ;
+                               SaveNeighbor snDead = null ;
+                               for( int i = 0 ; i < computingClients.size() ; i++ )
+                               {
+                                       if( computingClients.get( i ).getSaveNeighbor().getIPHost().equalsIgnoreCase( ipDead ) ) 
+                                       {
+                                               snDead = computingClients.get( i ).getSaveNeighbor() ;
+                                               break ;
+                                       }
+                               }
                                                                
                                boolean ok = false ;
                                
@@ -458,7 +387,7 @@ public class Server extends UnicastRemoteObject implements ServicesServer
                                                        
                                                        ComputingClient ccl = new ComputingClient( clients.get(i) ) ;
                                                        clients.get( i ).setComputingClient( ccl ) ;
-                                                       ServicesClient sn = computingClients.get( pos ).getSaveNeighbor() ;
+                                                       SaveNeighbor sn = computingClients.get( pos ).getSaveNeighbor() ;
                                                        ccl.setSaveNeighbor( sn ) ;
                                                        computingClients.set( pos, ccl ) ;
 
@@ -470,39 +399,58 @@ public class Server extends UnicastRemoteObject implements ServicesServer
                                                        } catch( RemoteException e ) {
                                                                System.err.println( "Unable to indicate to client to retrieve last save!" ) ;
                                                                e.printStackTrace() ;
+                                                               yield() ;
                                                        }
                                                                
                                                        if( res == 0 )
                                                        {
                                                                ok = true ;
+                                                               
+                                                               boolean ok_new = false, ok_old = false ;
                                                                        
-                                                                       // replace dead client in vmIPs
+                                                               // replace dead client in vmIPs
                                                                for( int j = 0 ; j < vmIPs.size() ; j++ )
                                                                {
+                                                                       if( vmIPs.get( j ).getHostIP().equalsIgnoreCase( computingClients.get( pos ).getClient().getIP() ) )
+                                                                       {
+                                                                               vmIPs.get( j ).setHostIP( "" ) ;
+                                                                               ok_new = true ;
+                                                                       }
                                                                        if( vmIPs.get( j ).getHostIP().equalsIgnoreCase( ipDead ) )
                                                                        {
                                                                                String vmIP = vmIPs.get( j ).getVmIP() ;
                                                                                vmIPs.get( j ).setHostIP( computingClients.get( pos ).getClient().getIP() ) ;
-                                                                                       
+                                                                               ok_old = true ;
+                                                                               
                                                                                try {
                                                                                        computingClients.get( pos ).getClient().getStub().setIPVM( vmIP ) ;
                                                                                } catch( RemoteException e ) {
                                                                                        System.err.println( "Unable to set the new VM IP on the replacing client!" ) ;
                                                                                        e.printStackTrace() ;
+                                                                                       yield() ;
+                                                                               }
+                                                                               
+                                                                               if( ok_new && ok_old )
+                                                                               {
+                                                                                       break ;
                                                                                }
-                                                                               break ;
                                                                        }
                                                                }
+                                                               
+                                                               // Replacing in RunningApplication
+                                                               applications.get( ind ).replaceComputingClient( cc, ccl ) ;
+                                                               
+                                                               for( int l = 0 ; l < applications.get( ind ).getComputingClients().size() ; l++ )
+                                                               {
+                                                                       applications.get( ind ).getComputingClients().get( l ).setSaveRequest( false ) ;
+                                                               }
+                                                               
                                                                        
                                                                System.out.println( "Successful redeployment of the VM." ) ;
                                                        } else {
                                                                System.err.println( "Unable to deploy the save on the new computing client!" ) ;
                                                        }
                                                }
-//                                             } else {
-//                                                     System.err.println( "Problem while launching the VM on " 
-//                                                                     + clients.get(i).getName() + "!" ) ;
-//                                             }
                                                        
                                                if( ok )
                                                {
@@ -510,7 +458,7 @@ public class Server extends UnicastRemoteObject implements ServicesServer
                                                        {
                                                                try {
                                                                        computingClients.get( k ).getClient().getStub().
-                                                                               replaceSavingNeighbor( ipDead, clients.get( i ).getStub() ) ;
+                                                                               replaceSaveNeighbor( snDead, new SaveNeighbor( clients.get( i ).getStub() ) ) ;
                                                                } catch( RemoteException e ) {
                                                                        System.err.println( "Unable to inform " + computingClients.get( k ).getClient().getName() +
                                                                                        " of the replacement of a save neighbor!" ) ;
@@ -552,7 +500,7 @@ public class Server extends UnicastRemoteObject implements ServicesServer
                @Override
                public void run() 
                {
-                       boolean change ;
+                       boolean change, dead ;
                        
                        while( run )
                        {
@@ -565,49 +513,72 @@ public class Server extends UnicastRemoteObject implements ServicesServer
                                {
                                        ConnectedClient cl = it.next() ;
                                        cl.incTimeout() ;
+                                       dead = false ;
                                        
-                                       if( cl.getTimeout() > max_timeout )
+                                       if( cl.getTimeout() > max_timeout || cl.getFail() )
                                        {
-                                               System.out.println( "Disconnection of " + cl.getName() ) ;
-                                               if( cl.getStatus().equalsIgnoreCase( "running" ) || cl.getStatus().equalsIgnoreCase( "saving" ) )
+                                               dead = true ;
+                                               if( ! cl.getFail() )
+                                               {
+                                                       try {
+                                                               cl.getStub().echo() ;
+                                                               cl.resetTimeout() ;
+                                                               dead = false ;
+                                                       } catch( RemoteException e ) {
+                                                               dead = true ;
+                                                       }
+                                               } 
+                                               
+                                               if( dead )
                                                {
-                                                       System.out.println( "A VM was running on it!!" ) ;
-                                                       System.out.println( "I will redeploy a save and restart all VM ..." ) ;
+                                                       System.out.println( "Disconnection of " + cl.getName() ) ;
+                                                       if( cl.getStatus().equalsIgnoreCase( "running" ) || cl.getStatus().equalsIgnoreCase( "saving" ) )
+                                                       {
+                                                               System.out.println( "A VM was running on it!!" ) ;
+                                                               System.out.println( "I will redeploy a save and restart all VM ..." ) ;
                                
-//                                                     for( int i = 0 ; i < computingClients.size() ; i++ )
-//                                                     {
-//                                                             if( computingClients.get( i ).getClient().getIP().equals( cl.getIP() ) )
+//                                                             for( int i = 0 ; i < computingClients.size() ; i++ )
 //                                                             {
-//                                                                     computingClients.remove( i ) ;
-//                                                                     break ;
+//                                                                     if( computingClients.get( i ).getClient().getIP().equals( cl.getIP() ) )
+//                                                                     {
+//                                                                             computingClients.remove( i ) ;
+//                                                                             break ;
+//                                                                     }
 //                                                             }
-//                                                     }
-                                                       synchronized( counter ){
-                                                               counter.inc() ;}
+                                                               synchronized( counter )
+                                                               {
+                                                                       counter.inc() ;
+                                                               }
                                                                
-                                                       
-                                                       new Server.FaultManager( cl ).start() ;
-                                                       nb_disconnections_computing++ ;
-                                               } else {
-                                                       System.out.println( "There was no VM running on it." ) ;
-                                                       System.out.println( "Maybe it will come back later :)" ) ;
-                                               }
+                                                               new Server.FaultManager( cl ).start() ;
+                                                               nb_disconnections_computing++ ;
+                                                       } else {
+                                                               System.out.println( "There was no VM running on it." ) ;
+                                                               System.out.println( "Maybe it will come back later :)" ) ;
+                                                       }
                                                
-                                               it.remove() ;
-                                               nb_disconnections++ ;
-                                               change = true ;
+                                                       synchronized( clients )
+                                                       {
+                                                               it.remove() ;
+                                                       }
+                                                       nb_disconnections++ ;
+                                                       change = true ;
+                                               }
                                        }
                                }
                                
                                if( change )
                                {
-                                       if( clients.size() == 0 )
+                                       synchronized( clients )
                                        {
-                                               System.out.println( "There is no client connected." ) ;
-                                       } else if( clients.size() == 1 ) {
-                                               System.out.println( "There is one client connected." ) ;
-                                       } else {
-                                               System.out.println( "There are " + clients.size() + " clients connected." ) ;
+                                               if( clients.size() == 0 )
+                                               {
+                                                       System.out.println( "There is no client connected." ) ;
+                                               } else if( clients.size() == 1 ) {
+                                                       System.out.println( "There is one client connected." ) ;
+                                               } else {
+                                                       System.out.println( "There are " + clients.size() + " clients connected." ) ;
+                                               }
                                        }
                                }
                                
@@ -626,6 +597,7 @@ public class Server extends UnicastRemoteObject implements ServicesServer
                                                        } catch( RemoteException e ) {
                                                                System.err.println( "Unable to invoke emergency stop signal on " + clients.get( i ).getName() ) ;
                                                                e.printStackTrace() ;
+                                                               yield() ;
                                                        }
                                                }
                                        }
@@ -645,26 +617,41 @@ public class Server extends UnicastRemoteObject implements ServicesServer
                                                                counter.wait() ;
                                                        } catch( InterruptedException e ) {
                                                                e.printStackTrace() ;
+                                                               yield() ;
                                                        }
                                                }
                                        }
                                        
-                                       for( int  i = 0 ; i < computingClients.size() ; i++ )
+                                       for( int i = 0 ; i < applications.get( ind ).getComputingClients().size() ; i++ )
                                        {
-                                               final ServicesClient sc = computingClients.get( i ).getClient().getStub() ;
+                                               applications.get( ind ).getComputingClients().get( i ).setRestartOk( false ) ;
                                                
-                                               new Thread( new Runnable() {
-                                                       
-                                                       @Override
-                                                       public void run() 
-                                                       {
-                                                               try {
-                                                                       sc.restartVMAfterCrash() ;
-                                                               } catch( RemoteException e ) {
-                                                                       e.printStackTrace() ;
-                                                               }
-                                                       }
-                                               } ).start() ;
+                                               new RestartVM( applications.get( ind ).getComputingClients().get( i ).getClient() ).start() ;
+                                               
+//                                             final ServicesClient sc = applications.get( ind ).getComputingClients().get( i ).getClient().getStub() ;
+                                               
+//                                             new Thread( new Runnable() {
+//                                                     
+//                                                     @Override
+//                                                     public void run() 
+//                                                     {
+//                                                             try {
+//                                                                     if( sc.restartVMAfterCrash() != 0 )
+//                                                                     {
+//                                                                             System.err.println( "Problem while restarting VM on " +sc.getName() + "!" ) ;
+//                                                                     }
+//                                                             } catch( RemoteException e ) {
+//                                                                     try {
+//                                                                             System.err.println( "Problem while restarting VM on " + sc.getName() + "!" ) ;
+//                                                                     } catch( RemoteException e1 ) {
+//                                                                             System.err.println( "Problem while restarting a VM!" ) ;
+//                                                                             e1.printStackTrace() ;
+//                                                                     }
+//                                                                     e.printStackTrace() ;
+//                                                                     yield() ;
+//                                                             }
+//                                                     }
+//                                             } ).start() ;
                                        }
                                }
                                
@@ -673,6 +660,7 @@ public class Server extends UnicastRemoteObject implements ServicesServer
                                        Thread.sleep( 2000 ) ;
                                } catch( InterruptedException e ) {
                                        e.printStackTrace() ;
+                                       yield() ;
                                }
                        }
                }
@@ -709,10 +697,13 @@ public class Server extends UnicastRemoteObject implements ServicesServer
                                try {
                                        computingClients.get( i ).getClient().getStub().saveOk() ;
                                } catch (RemoteException e) {
-                                       e.printStackTrace();
+                                       System.err.println( "Unable to invoke the saveOk method on " + computingClients.get( i ).getClient().getName() ) ;
+                                       e.printStackTrace() ;
                                }
                                computingClients.get( i ).setSaveStatus( false ) ;
                        }
+                       
+                       applications.get( ind ).setLastSaveDate( System.currentTimeMillis() ) ;
                }
                
                return 0 ;
@@ -728,49 +719,118 @@ public class Server extends UnicastRemoteObject implements ServicesServer
                                if( computingClients.get( i ).getClient().getIP().equalsIgnoreCase( _ip ) ) 
                                {
                                        computingClients.get( i ).setLastSave( _saveName ) ;
-                                       System.out.println( "Save name successfully change for " + _ip ) ;
+                                       System.out.println( "Save name successfully changed on " + computingClients.get( i ).getClient().getName() ) ;
                                        return 0 ;
                                }
                        }
+                       
+                       System.err.println( "Unable to found computing client with IP " + _ip + "!" ) ;
+                       return 1 ;
                }
                
+               System.err.println( "Unable to change save name. IP or save name empty ! (IP: " + _ip + " ; save name: " + _saveName +")" ) ;
+               
                return 1 ;
        }
 
+       
        @Override
        public ArrayList<ServicesClient> startApplication( int _nb ) 
        {
                int nb = clients.size() - computingClients.size() ;
                
-               if( nb > _nb )
+               if( nb > _nb && ! running )
                {
-                       ArrayList<ServicesClient> ac = new ArrayList<ServicesClient>() ;
-                       ArrayList<ComputingClient> tmp = new ArrayList<Server.ComputingClient>() ;
+                       running = true ;
+                       
+                       final ArrayList<ServicesClient> ac = new ArrayList<ServicesClient>() ;
+                       final ArrayList<ComputingClient> tmp = new ArrayList<ComputingClient>() ;
+                       
+                       RunningApplication app = new RunningApplication( "Test" ) ;
                        
                        int i = 0 ;
+                       boolean ok ;
                        
                        while( i < clients.size() && ac.size() < _nb )
                        {
-                               if( clients.get(i).getStatus().equalsIgnoreCase( "connected" ) ) 
+                               ok = false ;
+                               if( clients.get( i ).getStatus().equalsIgnoreCase( "connected" ) ) 
                                {
-                                       int res = 1 ;
-                                       try {
-                                               res = clients.get( i ).getStub().startVM( 0 ) ;
-                                       } catch( RemoteException e ) {
-                                               e.printStackTrace();
+                                       synchronized( startingClients )
+                                       {
+                                               while( ac.size() + startingClients.getNb() >= _nb )
+                                               {
+                                                       if( ac.size() == _nb ) break ;
+                                                       
+                                                       try {
+                                                               startingClients.wait() ;
+                                                       } catch( InterruptedException e ) {
+                                                               e.printStackTrace() ;
+                                                       }
+                                               }
+                                               
+                                               if( ac.size() < _nb )
+                                               {
+                                                       startingClients.inc() ;
+                                                       ok = true ;
+                                               }
                                        }
                                        
-                                       if( res == 0 )
+                                       if( ok )
                                        {
-                                               ac.add( clients.get( i ).getStub() ) ;
-                                               clients.get( i ).setStatus( "running" ) ;
-                                               ComputingClient cl = new ComputingClient( clients.get( i ) ) ;
-                                               clients.get( i ).setComputingClient( cl ) ;
-                                               computingClients.add( cl ) ;
-                                               tmp.add( cl ) ;
-                                       } else {
-                                               System.err.println( "Problem while launching the VM on " 
-                                                               + clients.get(i).getName() + "!" ) ;
+                                               synchronized( limitThread )
+                                               {
+                                                       while( limitThread.getNb() >= maxThread )
+                                                       {
+                                                               try {
+                                                                       limitThread.wait() ;
+                                                               } catch (InterruptedException e) {
+                                                                       e.printStackTrace();
+                                                               }
+                                                       } 
+                                                       
+                                                       limitThread.inc() ;
+                                               }
+                                               
+                                               final int indice = i ;
+                                               new Thread( new Runnable()
+                                               {       
+                                                       @Override
+                                                       public void run() 
+                                                       {
+                                                               int res = 1 ;
+                                                               try {
+                                                                       res = clients.get( indice ).getStub().startVM( 0 ) ;
+                                                               } catch( RemoteException e ) {
+                                                                       e.printStackTrace() ;
+                                                               }
+                                                               
+                                                               if( res == 0 )
+                                                               {
+                                                                       ac.add( clients.get( indice ).getStub() ) ;
+                                                                       clients.get( indice ).setStatus( "running" ) ;
+                                                                       ComputingClient cl = new ComputingClient( clients.get( indice ) ) ;
+                                                                       clients.get( indice ).setComputingClient( cl ) ;
+                                                                       computingClients.add( cl ) ;
+                                                                       tmp.add( cl ) ;
+                                                               } else {
+                                                                       System.err.println( "Problem while launching the VM on " 
+                                                                                       + clients.get( indice ).getName() + "!" ) ;
+                                                               }
+                                                               
+                                                               synchronized( limitThread )
+                                                               {
+                                                                       limitThread.dec() ;
+                                                                       limitThread.notifyAll() ;
+                                                               }
+                                                               
+                                                               synchronized( startingClients )
+                                                               {
+                                                                       startingClients.dec() ;
+                                                                       startingClients.notifyAll() ;
+                                                               }
+                                                       }
+                                               }).start() ;
                                        }
                                }
                                
@@ -779,6 +839,10 @@ public class Server extends UnicastRemoteObject implements ServicesServer
                        
                        if( ac.size() == _nb )
                        {
+                               app.setComputingClients( tmp ) ;
+                               app.setRunning( true ) ;
+//                             app.setStartTime( System.currentTimeMillis() ) ;
+                               
                                int index, index2 ;
                                /* Choosing save neighbors */
                                for( i = 0 ; i < tmp.size() ; i++ )
@@ -792,7 +856,12 @@ public class Server extends UnicastRemoteObject implements ServicesServer
                                                {
                                                        System.err.println( "Problem in ComputingClients list!" ) ;
                                                } else {
-                                                       computingClients.get( index ).setSaveNeighbor( computingClients.get( index2 ).getClient().getStub() ) ;
+                                                       try {
+                                                               computingClients.get( index ).setSaveNeighbor( new SaveNeighbor( computingClients.get( index2 ).getClient().getStub() )) ;
+                                                       } catch( RemoteException e ) {
+                                                               System.err.println( "Unable to create the save neighbor!" ) ;
+                                                               e.printStackTrace() ;
+                                                       }
                                                }
                                        } else {
                                                index = computingClients.indexOf( tmp.get( i ) ) ;
@@ -802,45 +871,236 @@ public class Server extends UnicastRemoteObject implements ServicesServer
                                                {
                                                        System.err.println( "Problem in ComputingClients list!" ) ;
                                                } else {
-                                                       computingClients.get( index ).setSaveNeighbor( computingClients.get( index2 ).getClient().getStub() ) ;
+                                                       try {
+                                                               computingClients.get( index ).setSaveNeighbor( new SaveNeighbor( computingClients.get( index2 ).getClient().getStub() ) ) ;
+                                                       } catch( RemoteException e ) {
+                                                               System.err.println( "Unable to create the save neighbor!" ) ;
+                                                               e.printStackTrace() ;
+                                                       }
                                                }
                                        }
                                }
                        }
                        
-                       /* Cleaning */
-                       tmp.clear() ;
-                       tmp = null ;
+                       applications.add( app ) ;
+                       
+                       ind = applications.indexOf( app ) ;
                        
                        return ac ;
                }
                
                return null ;
        }
+       
+       
+       @Override
+       public void requestSave( String _ip )
+       {
+               try {
+                       semaSave.acquire() ;
+               } catch( InterruptedException e ) {
+                       System.err.println( "Unable to obtain the semaphore for semaSave!" ) ;
+                       e.printStackTrace() ;
+               }
+               
+               final String ip = _ip ;
+               
+               new Thread( new Runnable() {
+                       
+                       @Override
+                       public void run() 
+                       {
+                               treatRequestSave( ip ) ;
+                       }
+               } ).start() ;
+       }
 
-
+       
+       public void treatRequestSave( String _ip )
+       {
+               if( applications.size() > 0 && _ip != null && _ip.length() > 0 )
+               {
+                       if( (System.currentTimeMillis() - applications.get( ind ).getLastSaveDate()) > save_interleave )
+                       {
+                               // Mark it as a requester
+                               for( int i = 0 ; i < applications.get( ind ).getComputingClients().size() ; i++ )
+                               {
+                                       if( applications.get( ind ).getComputingClients().get( i ).getClient().getIP().equalsIgnoreCase( _ip ) )
+                                       {
+                                               applications.get( ind ).getComputingClients().get( i ).setSaveRequest( true ) ;
+                                                                                               
+                                               break ;
+                                       }
+                               }
+                               
+                               semaSave.release() ;
+                               
+                               // Is every body ok?
+                               boolean ok = false ;
+                               for( int i = 0 ; i < applications.get( ind ).getComputingClients().size() ; i++ )
+                               {
+                                       if( i == 0 )
+                                       {
+                                               ok = applications.get( ind ).getComputingClients().get( i ).getSaveRequest() ;
+                                       } else {
+                                               ok = ok & applications.get( ind ).getComputingClients().get( i ).getSaveRequest() ;     
+                                       }
+                                       
+                                       if( ! ok )
+                                       {
+                                               break ;
+                                       }
+                               }
+                               
+                               if( ok )
+                               {
+//                                     try {
+//                                             Thread.sleep( 5000 ) ;
+//                                     } catch( InterruptedException e1 ) {
+//                                             e1.printStackTrace() ;
+//                                     }
+                                       
+                                       for( int i = 0 ; i < applications.get( ind ).getComputingClients().size() ; i++ )
+                                       {
+                                               try {
+                                                       applications.get( ind ).getComputingClients().get( i ).getClient().getStub().responseSave( true ) ;
+                                                       applications.get( ind ).getComputingClients().get( i ).setSaveRequest( false ) ;                                                        
+                                               } catch( RemoteException e ) {
+                                                       System.err.println( "Unable to send the save request response to " +
+                                                                       applications.get( ind ).getComputingClients().get( i ).getClient().getName() + "!" ) ;
+                                                       e.printStackTrace() ; 
+                                               }
+                                       }
+                                       
+                                       applications.get( ind ).setLastSaveDate( System.currentTimeMillis() ) ;
+                               }
+                               
+                       } else {
+                               semaSave.release() ;
+                               
+                               for( int i = 0 ; i < applications.get( ind ).getComputingClients().size() ; i++ )
+                               {
+                                       if( applications.get( ind ).getComputingClients().get( i ).getClient().getIP().equalsIgnoreCase( _ip ) )
+                                       {
+                                               try {
+                                                       applications.get( ind ).getComputingClients().get( i ).getClient().getStub().responseSave( false ) ;
+                                               } catch( RemoteException e ) {
+                                                       System.err.println( "Unable to send the save request response to " +
+                                                                       applications.get( ind ).getComputingClients().get( i ).getClient().getName() + "!" ) ;
+                                                       e.printStackTrace() ; 
+                                               }
+                                               break ;
+                                       }
+                               }
+                       }
+               } else {
+                       semaSave.release() ;
+                       System.err.println( "!! Serious problem in treatRequestSave method!!" ) ;
+               }
+       }       
+       
+       
+       @Override
+       public void restartOk( String _ip )
+       {
+               if( applications.size() > 0 && _ip != null && _ip.length() > 0 )
+               {
+                       System.out.println( "Client " + _ip + " has finished to restart ("+applications.get( ind ).getComputingClients().size()+") ... " ) ;
+//                     if( (System.currentTimeMillis() - applications.get( ind ).getLastSaveDate()) > save_interleave )
+                       {
+                               // Has it already finished?
+                               for( int i = 0 ; i < applications.get( ind ).getComputingClients().size() ; i++ )
+                               {
+                                       if( applications.get( ind ).getComputingClients().get( i ).getClient().getIP().equalsIgnoreCase( _ip ) )
+                                       {
+                                               applications.get( ind ).getComputingClients().get( i ).setRestartOk( true ) ;
+                                                                                               
+                                               break ;
+                                       }
+                               }
+                               
+                               // Is everybody ok?
+                               boolean ok = false ;
+                               for( int i = 0 ; i < applications.get( ind ).getComputingClients().size() ; i++ )
+                               {
+                                       if( i == 0 )
+                                       {
+                                               ok = applications.get( ind ).getComputingClients().get( i ).getRestartOk() ;
+                                       } else {
+                                               ok = ok & applications.get( ind ).getComputingClients().get( i ).getRestartOk() ;       
+                                       }
+                                       
+                                       if( ! ok )
+                                       {
+                                               break ;
+                                       }
+                               }
+                               
+                               if( ok )
+                               {
+                                       applications.get( ind ).setLastSaveDate( System.currentTimeMillis() ) ;
+                                       
+                                       for( int i = 0 ; i < applications.get( ind ).getComputingClients().size() ; i++ )
+                                       {
+                                               applications.get( ind ).getComputingClients().get( i ).setRestartOk( false ) ;
+                                       }
+                               }
+                               
+                       }
+               }
+       }       
+       
+       
+       @Override
+       public void goApplication()
+       {
+               synchronized( applications ) {
+               if( running && applications.get( ind ).getStartTime() != 0 )
+               {
+                       applications.get( ind ).setStartTime( System.currentTimeMillis() ) ;
+                       applications.get( ind ).setLastSaveDate( System.currentTimeMillis() ) ;
+               }}
+       }
+       
 
        @Override
        public void endApplication() 
        {
-               Iterator<ComputingClient> it = computingClients.iterator() ;
-               
-               while( it.hasNext() )
+               synchronized( applications )
                {
-                       ComputingClient cl = it.next() ;
+                       if( running )
+                       {
+                               applications.get( ind ).setEndTime( System.currentTimeMillis() ) ;
+                               applications.get( ind ).setRunning( false ) ;
+                               applications.get( ind ).clear() ;
+                       
+                               Iterator<ComputingClient> it = computingClients.iterator() ;
+               
+                               while( it.hasNext() )
+                               {
+                                       ComputingClient cl = it.next() ;
 
-                       try {
-                               cl.getClient().getStub().stopVM() ;
-                       } catch (RemoteException e) {
-                               e.printStackTrace();
-                       }
+                                       try {
+                                               cl.getClient().getStub().emergencyStop() ;
+                                       } catch (RemoteException e) {
+                                               e.printStackTrace();
+                                       }
                        
-                       cl.getClient().setStatus( "connected" ) ;
-                       cl.getClient().setComputingClient( null ) ;
-                       it.remove() ;
-                       cl = null ;
-               }
+                                       cl.getClient().setStatus( "connected" ) ;
+                                       cl.getClient().setComputingClient( null ) ;
+                                       it.remove() ;
+                                       cl = null ;
+                               }
                
+                       
+                               applications.get( ind ).clear() ;
+                       
+                               running = false ;
+                       
+                               System.out.println( "Application " + applications.get( ind ).getName() + " ends in " + 
+                                       applications.get( ind ).getExecutionTime() + " seconds." ) ;
+                       }
+               }
        }
 
 
@@ -863,10 +1123,9 @@ public class Server extends UnicastRemoteObject implements ServicesServer
        }
        
        
-       public Integer deployVM( String _name, String _archive, String _directory )
+       public Integer deployVM( final String _name, final String _archive, final String _directory )
        {
-               int pb = -1 ;
-               int nb = 0 ;
+               int nb = 0, pb = 0 ;
                
                if( _name != null && _name.length() > 0 && _archive != null && _name.length() > 0 
                                && _directory != null && _directory.length() > 0 )
@@ -888,113 +1147,161 @@ public class Server extends UnicastRemoteObject implements ServicesServer
                        file = null ;
                        
                        // TODO do a better deployment !!
-                       int ret ;
-                       boolean error ;
+//                     int ret ;
+//                     boolean error, ok, server ;
+//                     ArrayList<ConnectedClient> deployed = new ArrayList<ConnectedClient>() ;
                        
-                       pb = 0 ;
+//                     boolean server = true ;
+//                     boolean ok ;
                        
                        for( int i = 0 ; i < clients.size() ; i++ )
                        {
-                               ret = 1 ;
-                               error = false ;
-                               try {
-                                       ret = clients.get( i ).getStub().deployVM( _name, _archive, _directory ) ;
-                               } catch( RemoteException e ) {
-                                       System.err.println( "Unable to deploy the VM on " + clients.get( i ).getName() + "!" ) ;
-                                       e.printStackTrace() ;
-                               }
-                               
-                               // The client does not have the archive, we have to send it.
-                               if( ret == 2 )
-                               {
-                                       System.out.print( "Sending VM archive to " + clients.get( i ).getName() + " ... " ) ;
+//                             ret = 1 ;
+                               nb++ ;
+//                             error = false ;
+//                             ok = false ;
+                               if( clients.get( i ).getStatus().equalsIgnoreCase( "connected" ) )
+                               {                                       
+                                       synchronized( limitThread )
+                                       {
+                                               while( limitThread.getNb() >= maxThread )
+                                               {
+                                                       try {
+                                                               limitThread.wait() ;
+                                                       } catch (InterruptedException e) {
+                                                               e.printStackTrace();
+                                                       }
+                                               } 
+       
+                                               limitThread.inc() ;
+                                       }
                                        
-                                       String wd = "" ;
-                                       String snIP = "" ;
-                                       error = false ;
+                                       final int indice = i ;
+                                       new Thread( new Runnable() {
+
+                                               @Override
+                                               public void run() {
+                                                       int ret = -1 ;
+                                                       boolean error = true  ;
+                                                       
+                                                       try {
+                                                               ret = clients.get( indice ).getStub().deployVM( _name, _archive, _directory ) ;
+                                                       } catch( RemoteException e ) {
+                                                               System.err.println( "Unable to deploy the VM on " + clients.get( indice ).getName() + "!" ) ;
+                                                               e.printStackTrace() ;
+                                                       }
                                        
-                                       try {
-                                               wd = clients.get( i ).getStub().getWorkingDirectory() ;
-                                               snIP = clients.get( i ).getStub().getIPHost() ;
-                                       } catch (RemoteException e2) {
-                                               System.err.println( "Unable to retrieve information on " + clients.get( i ).getName() + "!" ) ;
-                                               e2.printStackTrace() ;
-                                               error = true ;
-                                               pb++ ;
-                                       }
+                                                       // The client does not have the archive, we have to send it.
+                                                       if( ret == 2 )
+                                                       {
+                                                               // Attention au multi-envois !!!
+                                                               System.out.print( "Sending VM archive to " + clients.get( indice ).getName() + " ... " ) ;
+                                       
+                                                               String wd = "" ;
+                                                               String snIP = "" ;
+                                                               error = false ;
+                                       
+                                                               try {
+                                                                       wd = clients.get( indice ).getStub().getWorkingDirectory() ;
+                                                                       snIP = clients.get( indice ).getStub().getIPHost() ;
+                                                               } catch (RemoteException e2) {
+                                                                       System.err.println( "Unable to retrieve information on " + clients.get( indice ).getName() + "!" ) ;
+                                                                       e2.printStackTrace() ;
+                                                                       error = true ;
+                                                               }
                                        
-                                       String[] command = new String[]{ "/usr/bin/scp", working_directory + "/" + _archive,
-                                                               snIP + ":" + wd } ;
+                                                               String[] command = new String[]{ "/usr/bin/scp", working_directory + "/" + _archive,
+                                                                               snIP + ":" + wd } ;
                                
-                                       if( ! error )
-                                       try {
-                                               Process proc = Runtime.getRuntime().exec( command ) ;
-                                               proc.waitFor() ;
+                                                               if( ! error )
+                                                               {
+                                                                       try {
+                                                                               Process proc = Runtime.getRuntime().exec( command ) ;
+                                                                               proc.waitFor() ;
                        
-                                               if( proc.exitValue() == 0 )
-                                               {
-                                                       System.out.println( "Initial VM archive successfully sent." ) ;
-                                               } else {
-                                                       System.err.println( "Initial VM archive not sent!" ) ;
-//                                                     printProcessError( p.getErrorStream() ) ;
-                                                       System.err.println( "Error: " + proc.exitValue() ) ;
-                                                       BufferedReader b = new BufferedReader( new InputStreamReader( proc.getErrorStream() ) ) ;
+                                                                               if( proc.exitValue() == 0 )
+                                                                               {
+                                                                                       System.out.println( "Initial VM archive successfully sent." ) ;
+                                                                               } else {
+                                                                                       System.err.println( "Initial VM archive not sent!" ) ;
+                                                                                       System.err.println( "Error: " + proc.exitValue() ) ;
+                                                                                       BufferedReader b = new BufferedReader( new InputStreamReader( proc.getErrorStream() ) ) ;
                                                        
-                                                       String l ;
-                                                       try {
-                                                               while( (l = b.readLine()) != null )
+                                                                                       String l ;
+                                                                                       try {
+                                                                                               while( (l = b.readLine()) != null )
+                                                                                               {
+                                                                                                       System.err.println( l ) ;
+                                                                                               }
+                                                                                       } catch( IOException e ) {
+                                                                                               e.printStackTrace() ;
+                                                                                       }
+                                                       
+                                                                                       error = true ;
+                                                                               }
+                                                                       } catch( IOException e ) {
+                                                                               System.err.println( "Error during initial VM archive send command: " ) ;
+                                                                               e.printStackTrace() ;
+                                                                               error = true ;
+                                                                       } catch( InterruptedException e ) {
+                                                                               e.printStackTrace() ;
+                                                                               error = true ;
+                                                                       }
+                                                               }
+                               
+                                                               
+                                                               if( ! error )
+                                                               {                               
+                                                                       // Second try ...
+                                                                       ret = 1 ;
+                                                                       try {
+                                                                               ret = clients.get( indice ).getStub().deployVM( _name, _archive, _directory ) ;
+                                                                       } catch( RemoteException e ) {
+                                                                               System.err.println( "Unable to deploy the VM on " + clients.get( indice ).getName() + "!" ) ;
+                                                                               e.printStackTrace() ;
+                                                                       }
+                                                               }
+                                                       }
+                               
+                                                       if( ret == 0 )
+                                                       {
+                                                               System.out.println( "Initial VM archive successfully deployed on " + clients.get( indice ).getName() + "." ) ;
+                                                               
+                                                               synchronized( deployingClients )
                                                                {
-                                                                       System.err.println( l ) ;
+                                                                       deployingClients.inc() ;
                                                                }
-                                                       } catch( IOException e ) {
-                                                                       e.printStackTrace() ;
                                                        }
                                                        
-                                                       error = true ;
-                                                       pb++ ;
+                                                       synchronized( limitThread )
+                                                       {
+                                                               limitThread.dec() ;
+                                                               limitThread.notifyAll() ;
+                                                       }
                                                }
-                                       } catch( IOException e ) {
-                                               System.err.println( "Error during initial VM archive send command: " ) ;
-                                               e.printStackTrace() ;
-                                               error = true ;
-                                               pb++ ;
-                                       } catch( InterruptedException e ) {
-                                               e.printStackTrace() ;
-                                               error = true ;
-                                               pb++ ;
-                                       }
-                               
-                               
-                                       if( error )
-                                       {
-                                               continue ;
-                                       }
-                               
-                                       // Second try ...
-                                       ret = 1 ;
-                                       try {
-                                               ret = clients.get( i ).getStub().deployVM( _name, _archive, _directory ) ;
-                                       } catch( RemoteException e ) {
-                                               System.err.println( "Unable to deploy the VM on " + clients.get( i ).getName() + "!" ) ;
-                                               e.printStackTrace() ;
-                                               pb++ ;
-                                       }
+                                       }).start() ;            
                                }
-                               
-                               if( ret == 0 )
-                               {
-                                       System.out.println( "Initial VM archive successfully deployed on " + clients.get( i ).getName() + "." ) ;
-                                       nb++ ;
+                       }
+               }
+               
+               synchronized( limitThread )
+               {
+                       while( limitThread.getNb() > 0  )
+                       {
+                               try {
+                                       limitThread.wait() ;
+                               } catch( InterruptedException e ) {
+                                       e.printStackTrace() ;
                                }
                        }
                }
                
-               if( pb > 0 )
+               if( nb - deployingClients.getNb() > 0 )
                {
                        if( pb == 1 )
                                System.err.println( "** " + pb + " machine is not deployed!" ) ;
                        if( pb > 1 )
-                               System.err.println( "** " + pb + " machine(s) are not deployed!" ) ;
+                               System.err.println( "** " + pb + " machines are not deployed!" ) ;
                }
                
                return nb ;
@@ -1006,6 +1313,80 @@ public class Server extends UnicastRemoteObject implements ServicesServer
                return working_directory ;
        }
        
+       
+       private class OperatingClients
+       {
+               private int nb ;
+               
+               OperatingClients() { nb = 0 ; }
+               
+               protected void inc() { nb++ ; }
+               
+               protected void dec() { nb-- ; }
+               
+               protected int getNb() { return nb ; }
+       }
+       
+       
+       private class LimitThread
+       {
+               private int nb ;
+               
+               LimitThread() { nb = 0 ; }
+               
+               protected void inc() { nb++ ; }
+               
+               protected void dec() { nb-- ; }
+               
+               protected int getNb() { return nb ; }
+       }
+       
+       
+       private class RestartVM extends Thread
+       {
+               private ConnectedClient cc ;
+               
+               protected RestartVM( ConnectedClient _cc )
+               {
+                       cc = _cc ;
+               }
+                       
+               public void run()
+               {
+                       boolean error = false ;
+                       if( cc != null )
+                       {
+                               try {
+                                       if( cc.getStub().restartVMAfterCrash() != 0 )
+                                       {
+                                               System.err.println( "Problem while restarting VM on " + cc.getName() + "!" ) ;
+                                               error = true ;
+                                       }
+                               } catch( RemoteException e ) {
+                                       e.printStackTrace() ;
+                                       error = true ;
+                                       yield() ;
+                               }
+                       } else {
+                               System.err.println( "The client to restart is null!" ) ;
+                       }
+                       
+                       if( error )
+                       {
+                               cc.setFail( true ) ;
+                               
+                               try {
+                                       System.out.print( "Trying to stop the client ... " ) ;
+                                       cc.getStub().stop() ;
+                                       System.out.println( "successful client stop." );
+                               } catch( RemoteException e ) {
+                                       System.out.println( "unsuccessful client stop!" ) ;
+                                       e.printStackTrace() ;
+                               }
+                       }
+               }
+       }
+       
 }
 
 /** La programmation est un art, respectons ceux qui la pratiquent !! **/