// until the state files merging utility is ready, the function is not really
// interesting, it selects 0 as the next gid each time
void
ReplicatorStateMachine::gidSelectionHandler( )
{
    REPLICATION_ASSERT( m_state == BACKUP || m_state == REPLICATION_LEADER );
    dprintf( D_ALWAYS, "ReplicatorStateMachine::gidSelectionHandler started\n");
    
    bool          areVersionsComparable = true;
    List<Version> actualVersionsList;
    Version       actualVersion;

    utilCopyList( actualVersionsList, m_versionsList );

    while( actualVersionsList.Next( actualVersion ) ) {
        if( ! m_myVersion.isComparable( actualVersion ) ) {
            areVersionsComparable = false;
            
            break;
        }    
    }
    actualVersionsList.Rewind( );

    if( areVersionsComparable ) {
        dprintf( D_ALWAYS, "ReplicatorStateMachine::gidSelectionHandler no "
				"need to select new gid\n" );
        return ;
    }
    int temporaryGid = 0;

    while( ( temporaryGid = rand( ) ) == m_myVersion.getGid( ) ) { }
    m_myVersion.setGid( temporaryGid );

    dprintf( D_ALWAYS, "ReplicatorStateMachine::gidSelectionHandler "
			"new gid selected: %d\n", temporaryGid );
    //myVersion.setSinfulString( daemonCore->InfoCommandSinfulString( ) );
}
// creating downloading transferer process and remembering its pid and creation
// time
bool
AbstractReplicatorStateMachine::download( const char* daemonSinfulString )
{
	ArgList  processArguments;
	processArguments.AppendArg( m_transfererPath.Value() );
	processArguments.AppendArg( "-f" );
	processArguments.AppendArg( "down" );
	processArguments.AppendArg( daemonSinfulString );
	processArguments.AppendArg( m_versionFilePath.Value() );
	processArguments.AppendArg( "1" );
	processArguments.AppendArg( m_stateFilePath.Value() );
	// Get arguments from this ArgList object for descriptional purposes.
	MyString	s;
	processArguments.GetArgsStringForDisplay( &s );
    dprintf( D_FULLDEBUG,
			 "AbstractReplicatorStateMachine::download creating "
			 "downloading condor_transferer process: \n \"%s\"\n",
			 s.Value( ) );

	// PRIV_ROOT privilege is necessary here to create the process
	// so we can read GSI certs <sigh>
	priv_state privilege = PRIV_ROOT;

	int transfererPid = daemonCore->Create_Process(
        m_transfererPath.Value( ),    // name
        processArguments,             // args
        privilege,                    // priv
        m_downloadReaperId,           // reaper id
        FALSE,                        // command port needed?
        FALSE,                        // command port needed?
        NULL,                         // env
        NULL,                         // cwd
        NULL                          // process family info
        );
    if( transfererPid == FALSE ) {
        dprintf( D_ALWAYS,
            "AbstractReplicatorStateMachine::download unable to create "
            "downloading condor_transferer process\n" );
        return false;
    } else {
        dprintf( D_FULLDEBUG,
            "AbstractReplicatorStateMachine::download downloading "
            "condor_transferer process created with pid = %d\n",
             transfererPid );
		REPLICATION_ASSERT( ! m_downloadTransfererMetadata.isValid() );
       /* Remembering the last time, when the downloading 'condor_transferer'
        * was created: the monitoring might be useful in possible prevention
        * of stuck 'condor_transferer' processes. Remembering the pid of the
        * downloading process as well: to terminate it when the downloading
        * process is stuck
        */
		m_downloadTransfererMetadata.set(transfererPid, time( NULL ) );
    }

    return true;
}
void
ReplicatorStateMachine::afterElectionStateHandler()
{
    dprintf( D_ALWAYS, "ReplicatorStateMachine::afterElectionStateHandler "
			"started\n" );
    REPLICATION_ASSERT(m_state != REPLICATION_LEADER);
   
	// we stay in VERSION_REQUESTING or VERSION_DOWNLOADING state
    // of newly joining node, we will go to LEADER_STATE later
    // upon receiving of IN_LEADER message from HAD 
    if( m_state == VERSION_REQUESTING || m_state == VERSION_DOWNLOADING ) {
        return ;
    }

	becomeLeader( );
}
// sends the version of the last execution time to all the replication daemons,
// then asks the pool replication daemons to send their own versions to it,
// sets a timer to wait till the versions are received
void
ReplicatorStateMachine::beforePassiveStateHandler()
{
    REPLICATION_ASSERT(m_state == VERSION_REQUESTING);
    
    dprintf( D_ALWAYS, 
			"ReplicatorStateMachine::beforePassiveStateHandler started\n" ); 
    broadcastVersion( REPLICATION_NEWLY_JOINED_VERSION );
    requestVersions( );

    dprintf( D_FULLDEBUG, "ReplicatorStateMachine::beforePassiveStateHandler "
			"registering version requesting timer\n" );
    m_versionRequestingTimerId = daemonCore->Register_Timer( 
		m_newlyJoinedWaitingVersionInterval,
       (TimerHandlercpp) &ReplicatorStateMachine::versionRequestingTimer,
       "Time to pass to VERSION_DOWNLOADING state", this );
}
bool
ReplicatorStateMachine::replicaSelectionHandler( Version& newVersion )
{
    REPLICATION_ASSERT( m_state == VERSION_DOWNLOADING || m_state == BACKUP );
    dprintf( D_ALWAYS, "ReplicatorStateMachine::replicaSelectionHandler "
			"started with my version = %s, #versions = %d\n",
             m_myVersion.toString( ).Value( ), m_versionsList.Number( ) );
    List<Version> actualVersionsList;
    Version myVersionCopy = m_myVersion;
    
    utilCopyList( actualVersionsList, m_versionsList );

	// in BACKUP state compares the received version with the local one
    if( m_state == BACKUP ) {        
		// compares the versions, taking only 'gid' and 'logicalClock' into
		// account - this is the reason for making the states equal
        myVersionCopy.setState( newVersion );

        return ! newVersion.isComparable( myVersionCopy ) || 
				 newVersion > myVersionCopy;
    }
	/* in VERSION_DOWNLOADING state selecting the best version from the list of
	 * received versions according to the policy defined by 
	 * 'replicaSelectionHandler', i.e. selecting the version with greatest
	 * 'logicalClock' value amongst a group of versions with the same gid
	 */
    actualVersionsList.Rewind( );
    
    if( actualVersionsList.IsEmpty( ) ) {
        return false;
    }
    Version version;
    Version bestVersion;
    // taking the first actual version as the best version in the meantime
    actualVersionsList.Next( bestVersion );
    dprintf( D_ALWAYS, "ReplicatorStateMachine::replicaSelectionHandler best "
			"version = %s\n", bestVersion.toString( ).Value( ) );
    
    while( actualVersionsList.Next( version ) ) {
        dprintf( D_ALWAYS, "ReplicatorStateMachine::replicaSelectionHandler "
				"actual version = %s\n", version.toString( ).Value( ) );
        if( version.isComparable( bestVersion ) && version > bestVersion ) {
            bestVersion = version;
        }
    }
    actualVersionsList.Rewind( );
    
	// compares the versions, taking only 'gid' and 'logicalClock' into
    // account - this is the reason for making the states equal
    myVersionCopy.setState( bestVersion );

	// either when the versions are incomparable or when the local version
	// is worse, the remote version must be downloaded
    if( myVersionCopy.isComparable( bestVersion ) && 
		myVersionCopy >= bestVersion ) {
        return false;
    }
    newVersion = bestVersion;
    dprintf( D_ALWAYS, "ReplicatorStateMachine::replicaSelectionHandler "
			"best version selected: %s\n", newVersion.toString().Value()); 
    return true;
}