Esempio n. 1
0
// FinalizeCompletedJobs
//------------------------------------------------------------------------------
void Server::FinalizeCompletedJobs()
{
    PROFILE_FUNCTION

    JobQueueRemote & jcr = JobQueueRemote::Get();
    while ( Job * job = jcr.GetCompletedJob() )
    {
        // get associated connection
        ClientState * cs = (ClientState *)job->GetUserData();

        MutexHolder mh( m_ClientListMutex );

        bool connectionStillActive = ( m_ClientList.Find( cs ) != nullptr );
        if ( connectionStillActive )
        {
            Node::State result = job->GetNode()->GetState();
            ASSERT( ( result == Node::UP_TO_DATE ) || ( result == Node::FAILED ) );

            MemoryStream ms;
            ms.Write( job->GetJobId() );
            ms.Write( job->GetNode()->GetName() );
            ms.Write( result == Node::UP_TO_DATE );
            ms.Write( job->GetSystemErrorCount() > 0 );
            ms.Write( job->GetMessages() );
            ms.Write( job->GetNode()->GetLastBuildTime() );

            // write the data - build result for success, or output+errors for failure
            ms.Write( (uint32_t)job->GetDataSize() );
            ms.WriteBuffer( job->GetData(), job->GetDataSize() );

            MutexHolder mh2( cs->m_Mutex );
            ASSERT( cs->m_NumJobsActive );
            cs->m_NumJobsActive--;

            Protocol::MsgJobResult msg;
            msg.Send( cs->m_Connection, ms );
        }
        else
        {
            // we might get here without finding the connection
            // (if the connection was lost before we completed)
        }

        FDELETE job;
    }
}
Esempio n. 2
0
// SendServerStatus
//------------------------------------------------------------------------------
void Server::SendServerStatus()
{
    PROFILE_FUNCTION

    MutexHolder mh( m_ClientListMutex );

    const ClientState * const * end = m_ClientList.End();
    for ( ClientState ** it = m_ClientList.Begin(); it !=  end; ++it )
    {
        ClientState * cs = *it;
        MutexHolder mh2( cs->m_Mutex );
        if ( cs->m_StatusTimer.GetElapsedMS() < Protocol::SERVER_STATUS_FREQUENCY_MS )
        {
            continue;
        }
        cs->m_StatusTimer.Start();

        Protocol::MsgServerStatus msg;
        msg.Send( cs->m_Connection );
    }
}
Esempio n. 3
0
// CheckWaitingJobs
//------------------------------------------------------------------------------
void Server::CheckWaitingJobs( const ToolManifest * manifest )
{
    // queue for start any jobs that may now be ready
#ifdef ASSERTS_ENABLED
    bool atLeastOneJobStarted = false;
#endif

    MutexHolder mhC( m_ClientListMutex );
    const ClientState * const * end = m_ClientList.End();
    for ( ClientState ** it = m_ClientList.Begin(); it!=end; ++it )
    {
        // For each connected client...
        ClientState * cs = *it;
        MutexHolder mh2( cs->m_Mutex );

        // .. check all jobs waiting for ToolManifests
        int32_t numJobs = (int32_t)cs->m_WaitingJobs.GetSize();
        for ( int32_t i=( numJobs -1 ); i >= 0; --i )
        {
            Job * job = cs->m_WaitingJobs[ i ];
            ToolManifest * manifestForThisJob = job->GetToolManifest();
            ASSERT( manifestForThisJob );
            if ( manifestForThisJob == manifest )
            {
                cs->m_WaitingJobs.EraseIndex( i );
                JobQueueRemote::Get().QueueJob( job );
                PROTOCOL_DEBUG( "Server: Job %x can now be started\n", job );
#ifdef ASSERTS_ENABLED
                atLeastOneJobStarted = true;
#endif
            }
        }
    }

    // We should only have called this function when a ToolChain sync was complete
    // so at least 1 job should have been waiting for it
    ASSERT( atLeastOneJobStarted );
}
Esempio n. 4
0
// FindNeedyClients
//------------------------------------------------------------------------------
void Server::FindNeedyClients()
{
    if ( m_ShouldExit )
    {
        return;
    }

    PROFILE_FUNCTION

    MutexHolder mh( m_ClientListMutex );

    // determine job availability
    int availableJobs = (int)WorkerThreadRemote::GetNumCPUsToUse();
    if ( availableJobs == 0 )
    {
        return;
    }
    ++availableJobs; // over request to parallelize building/network transfers

    ClientState ** iter = m_ClientList.Begin();
    const ClientState * const * end = m_ClientList.End();
    for ( ; iter != end; ++iter )
    {
        ClientState * cs = *iter;

        MutexHolder mh2( cs->m_Mutex );

        // any jobs requested or in progress reduce the available count
        int reservedJobs = cs->m_NumJobsRequested +
                           cs->m_NumJobsActive;
        availableJobs -= reservedJobs;
        if ( availableJobs <= 0 )
        {
            return;
        }
    }

    // we have some jobs available

    // sort clients to find neediest first
    m_ClientList.SortDeref();

    Protocol::MsgRequestJob msg;

    while ( availableJobs > 0 )
    {
        bool anyJobsRequested = false;

        iter = m_ClientList.Begin();
        for ( ; iter != end; ++iter )
        {
            ClientState * cs = *iter;

            MutexHolder mh2( cs->m_Mutex );

            size_t reservedJobs = cs->m_NumJobsRequested;

            if ( reservedJobs >= cs->m_NumJobsAvailable )
            {
                continue; // we've maxed out the requests to this worker
            }

            // request job from this client
            msg.Send( cs->m_Connection );
            cs->m_NumJobsRequested++;
            availableJobs--;
            anyJobsRequested = true;
        }

        // if we did a pass and couldn't request any more jobs, then bail out
        if ( anyJobsRequested == false )
        {
            break;
        }
    }
}
Esempio n. 5
0
//------------------------------------------------------------------------------
/*virtual*/ void Server::OnDisconnected( const ConnectionInfo * connection )
{
    ASSERT( connection );
    ClientState * cs = (ClientState *)connection->GetUserData();
    ASSERT( cs );

    // Unhook any jobs which are queued or in progress for this client
    // - deletes the queued jobs
    // - unhooks the UserData for in-progress jobs so the result is discarded on completion
    JobQueueRemote & jqr = JobQueueRemote::Get();
    jqr.CancelJobsWithUserData( cs );

    // check if any tool chain was being sync'd from this Client
    Array< ToolManifest * > cancelledManifests( 0, true );
    {
        MutexHolder manifestMH( m_ToolManifestsMutex );
        const ToolManifest * const * end = m_Tools.End();
        ToolManifest ** it = m_Tools.Begin();
        while ( it != end )
        {
            // if synchronizing from connection that was just disconnected...
            ToolManifest * tm = *it;
            if ( ( tm->IsSynchronized() == false ) &&
                    ( tm->GetUserData() == connection ) )
            {
                // ...flag any expected files as not synching
                tm->CancelSynchronizingFiles();
                tm->SetUserData( nullptr );
                cancelledManifests.Append( tm );
            }
            ++it;
        }
    }

    // free the serverstate structure
    MutexHolder mh( m_ClientListMutex );
    ClientState ** iter = m_ClientList.Find( cs );
    ASSERT( iter );
    m_ClientList.Erase( iter );

    // because we cancelled manifest syncrhonization, we need to check if other
    // connections are waiting for the same manifest
    {
        ClientState ** it = m_ClientList.Begin();
        const ClientState * const * end = m_ClientList.End();
        for ( ; it != end; ++it )
        {
            ClientState * otherCS = *it;

            MutexHolder mh2( otherCS->m_Mutex );
            const Job * const * jEnd = otherCS->m_WaitingJobs.End();
            for ( Job ** jIt = otherCS->m_WaitingJobs.Begin(); jIt != jEnd; ++jIt )
            {
                Job * j = *jIt;
                ToolManifest * jMan = j->GetToolManifest();
                if ( cancelledManifests.Find( jMan ) )
                {
                    RequestMissingFiles( otherCS->m_Connection, jMan );
                }
            }
        }
    }

    // This is usually null here, but might need to be freed if
    // we had the connection drop between message and payload
    FREE( (void *)( cs->m_CurrentMessage ) );

    // delete any jobs where we were waiting on Tool synchronization
    const Job * const * end = cs->m_WaitingJobs.End();
    for ( Job ** it=cs->m_WaitingJobs.Begin(); it!=end; ++it )
    {
        delete *it;
    }

    FDELETE cs;
}
Esempio n. 6
0
// LookForWorkers
//------------------------------------------------------------------------------
void Client::LookForWorkers()
{
	PROFILE_FUNCTION

	MutexHolder mh( m_ServerListMutex );

	const size_t numWorkers( m_ServerList.GetSize() );

	// find out how many connections we have now
	size_t numConnections = 0;
	for ( size_t i=0; i<numWorkers; i++ )
	{
		if ( m_ServerList[ i ].m_Connection )
		{
			numConnections++;
		}
	}

	// limit maximum concurrent connections
	if ( numConnections >= CONNECTION_LIMIT )
	{
		return;
	}

	// if we're connected to every possible worker already
	if ( numConnections == numWorkers )
	{
		return;
	}

	// randomize the start index to better distribute workers when there 
	// are many workers/clients - otherwise all clients will attempt to connect 
	// to the first CONNECTION_LIMIT workers
	Random r;
	size_t startIndex = r.GetRandIndex( (uint32_t)numWorkers );

	// find someone to connect to
	for ( size_t j=0; j<numWorkers; j++ )
	{
		const size_t i( ( j + startIndex ) % numWorkers );

		ServerState & ss = m_ServerList[ i ];
		if ( ss.m_Connection )
		{
			continue;
		}

		// ignore blacklisted workers
		if ( ss.m_Blacklisted )
		{
			continue;
		}

		// lock the server state
		MutexHolder mhSS( ss.m_Mutex );

		ASSERT( ss.m_Jobs.IsEmpty() );

		if ( ss.m_DelayTimer.GetElapsed() < CONNECTION_REATTEMPT_DELAY_TIME )
		{
			continue;
		}

		const ConnectionInfo * ci = Connect( m_WorkerList[ i ], Protocol::PROTOCOL_PORT );
		if ( ci == nullptr )
		{
			ss.m_DelayTimer.Start(); // reset connection attempt delay
		}
		else
		{
			const uint32_t numJobsAvailable( JobQueue::IsValid() ? (uint32_t)JobQueue::Get().GetNumDistributableJobsAvailable() : 0 );

			ci->SetUserData( &ss );
			ss.m_Connection = ci; // success!
			ss.m_NumJobsAvailable = numJobsAvailable;
			ss.m_StatusTimer.Start();

			// send connection msg
			Protocol::MsgConnection msg( numJobsAvailable );
			MutexHolder mh2( ss.m_Mutex );
			msg.Send( ci );
		}

		// limit to one connection attempt per iteration
		return;
	}
}
Esempio n. 7
0
bool palMinHeapTest() {
  palMinHeap<int> mh;
  mh.SetAllocator(g_DefaultHeapAllocator);
  mh.Insert(3);
  mh.Insert(999912);
  mh.Insert(66);
  mh.Insert(-3);
  mh.Insert(27);
  mh.Insert(0);
  mh.Insert(1);
  mh.Insert(1000000);

  int correct_order[] = {-3, 0, 1, 3, 27, 66, 999912, 1000000};
  int answer_index = 0;
  while (mh.IsEmpty() == false) {
    int answer = mh.FindMin();
    if (correct_order[answer_index] != answer) {
      palBreakHere();
    }
    mh.DeleteMin();
    answer_index++;
  }

  mh.Insert(3);
  mh.Insert(999912);
  mh.Insert(66);
  mh.Insert(-3);
  mh.Insert(27);
  mh.Insert(0);
  mh.Insert(1);
  mh.Insert(1000000);

  palMinHeap<int> mh2(mh);
  answer_index = 0;
  while (mh2.IsEmpty() == false) {
    int answer = mh2.FindMin();
    if (correct_order[answer_index] != answer) {
      palBreakHere();
    }
    mh2.DeleteMin();
    answer_index++;
  }
  palMinHeap<int> mh3;
  mh3.SetAllocator(g_DefaultHeapAllocator);
  mh3 = mh;

  answer_index = 0;
  while (mh3.IsEmpty() == false) {
    int answer = mh3.FindMin();
    if (correct_order[answer_index] != answer) {
      palBreakHere();
    }
    mh3.DeleteMin();
    answer_index++;
  }

  answer_index = 0;
  while (mh.IsEmpty() == false) {
    int answer = mh.FindMin();
    if (correct_order[answer_index] != answer) {
      palBreakHere();
    }
    mh.DeleteMin();
    answer_index++;
  }

  return true;
}