refactor: getPeerCandidates returns a std::vector (#2042)

Previously was a manually-malloced and freed array.
This commit is contained in:
Charles Kerr
2021-10-25 00:15:04 -05:00
committed by GitHub
parent 93d8a03d55
commit 775e30eefd

View File

@@ -68,7 +68,7 @@ static auto constexpr MaxUploadIdleSecs = int{ 60 * 5 };
// max number of peers to ask for per second overall. // max number of peers to ask for per second overall.
// this throttle is to avoid overloading the router // this throttle is to avoid overloading the router
static auto constexpr MaxConnectionsPerSecond = int{ 12 }; static auto constexpr MaxConnectionsPerSecond = size_t{ 12 };
// number of bad pieces a peer is allowed to send before we ban them // number of bad pieces a peer is allowed to send before we ban them
static auto constexpr MaxBadPiecesPerPeer = int{ 5 }; static auto constexpr MaxBadPiecesPerPeer = int{ 5 };
@@ -3632,7 +3632,7 @@ static void enforceSessionPeerLimit(tr_session* session, uint64_t now)
} }
} }
static void makeNewPeerConnections(tr_peerMgr* mgr, int max); static void makeNewPeerConnections(tr_peerMgr* mgr, size_t max);
static void reconnectPulse(evutil_socket_t /*fd*/, short /*what*/, void* vmgr) static void reconnectPulse(evutil_socket_t /*fd*/, short /*what*/, void* vmgr)
{ {
@@ -4016,36 +4016,6 @@ static uint64_t getPeerCandidateScore(tr_torrent const* tor, struct peer_atom co
return score; return score;
} }
#ifdef TR_ENABLE_ASSERTS
static bool checkBestScoresComeFirst(struct peer_candidate const* candidates, int n, int k)
{
uint64_t worstFirstScore = 0;
int const x = std::min(n, k) - 1;
for (int i = 0; i < x; i++)
{
if (worstFirstScore < candidates[i].score)
{
worstFirstScore = candidates[i].score;
}
}
for (int i = 0; i < x; i++)
{
TR_ASSERT(candidates[i].score <= worstFirstScore);
}
for (int i = x + 1; i < n; i++)
{
TR_ASSERT(candidates[i].score >= worstFirstScore);
}
return true;
}
#endif /* TR_ENABLE_ASSERTS */
static bool calculateAllSeeds(tr_swarm* swarm) static bool calculateAllSeeds(tr_swarm* swarm)
{ {
int nAtoms = 0; int nAtoms = 0;
@@ -4074,7 +4044,7 @@ static bool swarmIsAllSeeds(tr_swarm* swarm)
} }
/** @return an array of all the atoms we might want to connect to */ /** @return an array of all the atoms we might want to connect to */
static struct peer_candidate* getPeerCandidates(tr_session* session, int* candidateCount, int max) static std::vector<peer_candidate> getPeerCandidates(tr_session* session, size_t max)
{ {
time_t const now = tr_time(); time_t const now = tr_time();
uint64_t const now_msec = tr_time_msec(); uint64_t const now_msec = tr_time_msec();
@@ -4093,13 +4063,11 @@ static struct peer_candidate* getPeerCandidates(tr_session* session, int* candid
/* don't start any new handshakes if we're full up */ /* don't start any new handshakes if we're full up */
if (maxCandidates <= peerCount) if (maxCandidates <= peerCount)
{ {
*candidateCount = 0; return {};
return nullptr;
} }
/* allocate an array of candidates */ auto candidates = std::vector<peer_candidate>{};
peer_candidate* const candidates = tr_new(peer_candidate, atomCount); candidates.reserve(atomCount);
peer_candidate* walk = candidates;
/* populate the candidate array */ /* populate the candidate array */
for (auto* tor : session->torrents) for (auto* tor : session->torrents)
@@ -4139,26 +4107,22 @@ static struct peer_candidate* getPeerCandidates(tr_session* session, int* candid
if (isPeerCandidate(tor, atom, now)) if (isPeerCandidate(tor, atom, now))
{ {
uint8_t const salt = tr_rand_int_weak(1024); uint8_t const salt = tr_rand_int_weak(1024);
walk->tor = tor; candidates.push_back({ getPeerCandidateScore(tor, atom, salt), tor, atom });
walk->atom = atom;
walk->score = getPeerCandidateScore(tor, atom, salt);
++walk;
} }
} }
} }
auto const n_candidates = walk - candidates; // only keep the best `max` candidates
*candidateCount = n_candidates; if (std::size(candidates) > max)
if (n_candidates > max)
{ {
std::partial_sort( std::partial_sort(
candidates, std::begin(candidates),
candidates + max, std::begin(candidates) + max,
candidates + n_candidates, std::end(candidates),
[](auto const& a, auto const& b) { return a.score < b.score; }); [](auto const& a, auto const& b) { return a.score < b.score; });
candidates.resize(max);
} }
TR_ASSERT(checkBestScoresComeFirst(candidates, *candidateCount, max));
return candidates; return candidates;
} }
@@ -4207,7 +4171,7 @@ static void initiateConnection(tr_peerMgr* mgr, tr_swarm* s, struct peer_atom* a
atom->time = now; atom->time = now;
} }
static void initiateCandidateConnection(tr_peerMgr* mgr, struct peer_candidate* c) static void initiateCandidateConnection(tr_peerMgr* mgr, peer_candidate& c)
{ {
#if 0 #if 0
@@ -4217,18 +4181,13 @@ static void initiateCandidateConnection(tr_peerMgr* mgr, struct peer_candidate*
#endif #endif
initiateConnection(mgr, c->tor->swarm, c->atom); initiateConnection(mgr, c.tor->swarm, c.atom);
} }
static void makeNewPeerConnections(struct tr_peerMgr* mgr, int max) static void makeNewPeerConnections(struct tr_peerMgr* mgr, size_t max)
{ {
auto n = int{}; for (auto& candidate : getPeerCandidates(mgr->session, max))
struct peer_candidate* candidates = getPeerCandidates(mgr->session, &n, max);
for (int i = 0; i < n && i < max; ++i)
{ {
initiateCandidateConnection(mgr, &candidates[i]); initiateCandidateConnection(mgr, candidate);
} }
tr_free(candidates);
} }