bool Connection::send( const Connections& connections, Packet& packet, const void* data, const uint64_t dataSize, const bool isLocked ) { if( connections.empty( )) return true; if( dataSize <= 8 ) // fits in existing packet { if( dataSize != 0 ) memcpy( (char*)(&packet) + packet.size-8, data, dataSize ); return send( connections, packet, isLocked ); } const uint64_t headerSize = packet.size - 8; const uint64_t size = headerSize + dataSize; if( size > EQ_ASSEMBLE_THRESHOLD ) { // OPT: lock the connection and use two send() to avoid big memcpy packet.size = size; bool success = true; for( Connections::const_iterator i= connections.begin(); i<connections.end(); ++i ) { ConnectionPtr connection = *i; if( !isLocked ) connection->lockSend(); if( !connection->send( &packet, headerSize, true ) || !connection->send( data, dataSize, true )) { success = false; } if( !isLocked ) connection->unlockSend(); } return success; } char* buffer = (char*)alloca( size ); memcpy( buffer, &packet, packet.size-8 ); memcpy( buffer + packet.size-8, data, dataSize ); ((Packet*)buffer)->size = size; bool success = true; for( Connections::const_iterator i = connections.begin(); i < connections.end(); ++i ) { ConnectionPtr connection = *i; if( !connection->send( buffer, size, isLocked )) success = false; } return success; }
bool Connection::send( const Connections& connections, const Packet& packet, const bool isLocked ) { if( connections.empty( )) return true; bool success = true; for( Connections::const_iterator i= connections.begin(); i<connections.end(); ++i ) { ConnectionPtr connection = *i; if( !connection->send( &packet, packet.size, isLocked )) success = false; } return success; }
bool Connection::send( const Connections& connections, Packet& packet, const void* const* items, const uint64_t* sizes, const size_t nItems ) { if( connections.empty( )) return true; packet.size -= 8; const uint64_t headerSize = packet.size; for( size_t i = 0; i < nItems; ++i ) { EQASSERT( sizes[i] > 0 ); packet.size += sizes[ i ] + sizeof( uint64_t ); } bool success = true; for( Connections::const_iterator i = connections.begin(); i < connections.end(); ++i ) { ConnectionPtr connection = *i; connection->lockSend(); if( !connection->send( &packet, headerSize, true )) success = false; for( size_t j = 0; j < nItems; ++j ) if( !connection->send( &sizes[j], sizeof(uint64_t), true ) || !connection->send( items[j], sizes[j], true )) { success = false; } connection->unlockSend(); } return success; }
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; }