void ServerPool::InitConnections() { debug("Initializing connections in ServerPool"); m_mutexConnections.Lock(); NormalizeLevels(); m_Levels.clear(); for (Servers::iterator it = m_SortedServers.begin(); it != m_SortedServers.end(); it++) { NewsServer* pNewsServer = *it; pNewsServer->SetBlockTime(0); int iNormLevel = pNewsServer->GetNormLevel(); if (pNewsServer->GetNormLevel() > -1) { if ((int)m_Levels.size() <= iNormLevel) { m_Levels.push_back(0); } if (pNewsServer->GetActive()) { int iConnections = 0; for (Connections::iterator it = m_Connections.begin(); it != m_Connections.end(); it++) { PooledConnection* pConnection = *it; if (pConnection->GetNewsServer() == pNewsServer) { iConnections++; } } for (int i = iConnections; i < pNewsServer->GetMaxConnections(); i++) { PooledConnection* pConnection = new PooledConnection(pNewsServer); pConnection->SetTimeout(m_iTimeout); m_Connections.push_back(pConnection); iConnections++; } m_Levels[iNormLevel] += iConnections; } } } m_iGeneration++; m_mutexConnections.Unlock(); }
NNTPConnection* ServerPool::GetConnection(int iLevel, NewsServer* pWantServer, Servers* pIgnoreServers) { PooledConnection* pConnection = NULL; m_mutexConnections.Lock(); time_t tCurTime = time(NULL); if (iLevel < (int)m_Levels.size() && m_Levels[iLevel] > 0) { Connections candidates; candidates.reserve(m_Connections.size()); for (Connections::iterator it = m_Connections.begin(); it != m_Connections.end(); it++) { PooledConnection* pCandidateConnection = *it; NewsServer* pCandidateServer = pCandidateConnection->GetNewsServer(); if (!pCandidateConnection->GetInUse() && pCandidateServer->GetActive() && pCandidateServer->GetNormLevel() == iLevel && (!pWantServer || pCandidateServer == pWantServer || (pWantServer->GetGroup() > 0 && pWantServer->GetGroup() == pCandidateServer->GetGroup())) && (pCandidateConnection->GetStatus() == Connection::csConnected || !pCandidateServer->GetBlockTime() || pCandidateServer->GetBlockTime() + m_iRetryInterval <= tCurTime || pCandidateServer->GetBlockTime() > tCurTime)) { // free connection found, check if it's not from the server which should be ignored bool bUseConnection = true; if (pIgnoreServers && !pWantServer) { for (Servers::iterator it = pIgnoreServers->begin(); it != pIgnoreServers->end(); it++) { NewsServer* pIgnoreServer = *it; if (pIgnoreServer == pCandidateServer || (pIgnoreServer->GetGroup() > 0 && pIgnoreServer->GetGroup() == pCandidateServer->GetGroup() && pIgnoreServer->GetNormLevel() == pCandidateServer->GetNormLevel())) { bUseConnection = false; break; } } } pCandidateServer->SetBlockTime(0); if (bUseConnection) { candidates.push_back(pCandidateConnection); } } } if (!candidates.empty()) { // Peeking a random free connection. This is better than taking the first // available connection because provides better distribution across news servers, // especially when one of servers becomes unavailable or doesn't have requested articles. int iRandomIndex = rand() % candidates.size(); pConnection = candidates[iRandomIndex]; pConnection->SetInUse(true); } if (pConnection) { m_Levels[iLevel]--; } } m_mutexConnections.Unlock(); return pConnection; }