refactor: make tr_swarm.peers a std::vector (#3017)

This commit is contained in:
Charles Kerr 2022-04-29 08:32:15 -05:00 committed by GitHub
parent 5dbe1f4669
commit d487a5d8d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 81 additions and 121 deletions

View File

@ -220,7 +220,11 @@ public:
{
}
public:
[[nodiscard]] auto peerCount() const noexcept
{
return std::size(peers);
}
Handshakes outgoing_handshakes;
uint16_t interested_count = 0;
@ -239,9 +243,9 @@ public:
tr_peerMgr* const manager;
std::vector<std::unique_ptr<tr_peer>> webseeds;
std::vector<tr_peerMsgs*> peers;
tr_ptrArray pool = {}; /* struct peer_atom */
tr_ptrArray peers = {}; /* tr_peerMsgs */
tr_torrent* const tor;
@ -345,13 +349,6 @@ static tr_swarm* getExistingSwarm(tr_peerMgr* manager, tr_sha1_digest_t const& h
return tor == nullptr ? nullptr : tor->swarm;
}
static int peerCompare(void const* va, void const* vb)
{
auto const* const a = static_cast<tr_peer const*>(va);
auto const* const b = static_cast<tr_peer const*>(vb);
return tr_address_compare(tr_peerAddress(a), tr_peerAddress(b));
}
static struct peer_atom* getExistingAtom(tr_swarm const* cswarm, tr_address const* addr)
{
auto* swarm = const_cast<tr_swarm*>(cswarm);
@ -374,10 +371,9 @@ static void swarmFree(tr_swarm* s)
TR_ASSERT(!s->is_running);
TR_ASSERT(std::empty(s->outgoing_handshakes));
TR_ASSERT(tr_ptrArrayEmpty(&s->peers));
TR_ASSERT(s->peerCount() == 0);
tr_ptrArrayDestruct(&s->pool, (PtrArrayForeachFunc)tr_free);
tr_ptrArrayDestruct(&s->peers, nullptr);
s->stats = {};
delete s;
@ -768,10 +764,8 @@ void tr_peerMgrPieceCompleted(tr_torrent* tor, tr_piece_index_t p)
tr_swarm* const s = tor->swarm;
/* walk through our peers */
for (int i = 0, n = tr_ptrArraySize(&s->peers); i < n; ++i)
for (auto* const peer : s->peers)
{
auto* peer = static_cast<tr_peerMsgs*>(tr_ptrArrayNth(&s->peers, i));
// notify the peer that we now have this piece
peer->on_piece_completed(p);
@ -980,11 +974,6 @@ static struct peer_atom* ensureAtomExists(
return tor->max_connected_peers;
}
static int getPeerCount(tr_swarm const* s)
{
return tr_ptrArraySize(&s->peers);
}
static void createBitTorrentPeer(tr_torrent* tor, tr_peerIo* io, struct peer_atom* atom, tr_quark client)
{
TR_ASSERT(atom != nullptr);
@ -997,11 +986,12 @@ static void createBitTorrentPeer(tr_torrent* tor, tr_peerIo* io, struct peer_ato
peer->client = client;
atom->peer = peer;
tr_ptrArrayInsertSorted(&swarm->peers, peer, peerCompare);
swarm->peers.push_back(peer);
++swarm->stats.peer_count;
++swarm->stats.peer_from_count[atom->fromFirst];
TR_ASSERT(swarm->stats.peer_count == tr_ptrArraySize(&swarm->peers));
TR_ASSERT(swarm->stats.peer_count == swarm->peerCount());
TR_ASSERT(swarm->stats.peer_from_count[atom->fromFirst] <= swarm->stats.peer_count);
// TODO is this needed?
@ -1084,7 +1074,7 @@ static bool on_handshake_done(tr_handshake_result const& result)
{
tr_logAddTraceSwarm(s, fmt::format("banned peer {} tried to reconnect", tr_atomAddrStr(atom)));
}
else if (tr_peerIoIsIncoming(result.io) && getPeerCount(s) >= getMaxPeerCount(s->tor))
else if (tr_peerIoIsIncoming(result.io) && s->peerCount() >= getMaxPeerCount(s->tor))
{
/* too many peers already */
}
@ -1231,10 +1221,8 @@ void tr_peerMgrGotBadPiece(tr_torrent* tor, tr_piece_index_t pieceIndex)
tr_swarm* s = tor->swarm;
uint32_t const byteCount = tor->pieceSize(pieceIndex);
for (int i = 0, n = tr_ptrArraySize(&s->peers); i != n; ++i)
for (auto* peer : s->peers)
{
auto* const peer = static_cast<tr_peer*>(tr_ptrArrayNth(&s->peers, i));
if (peer->blame.test(pieceIndex))
{
tr_logAddTraceSwarm(
@ -1344,14 +1332,9 @@ int tr_peerMgrGetPeers(tr_torrent const* tor, tr_pex** setme_pex, uint8_t af, ui
struct peer_atom** atoms = nullptr;
if (list_mode == TR_PEERS_CONNECTED) /* connected peers only */
{
auto const** peers = (tr_peer const**)tr_ptrArrayBase(&s->peers);
atomCount = tr_ptrArraySize(&s->peers);
atomCount = s->peerCount();
atoms = tr_new(struct peer_atom*, atomCount);
for (int i = 0; i < atomCount; ++i)
{
atoms[i] = peers[i]->atom;
}
std::transform(std::begin(s->peers), std::end(s->peers), atoms, [](auto const* peer) { return peer->atom; });
}
else /* TR_PEERS_INTERESTING */
{
@ -1538,20 +1521,16 @@ void tr_peerMgrOnTorrentGotMetainfo(tr_torrent* tor)
/* some peer_msgs' progress fields may not be accurate if we
didn't have the metadata before now... so refresh them all... */
int const peerCount = tr_ptrArraySize(&tor->swarm->peers);
auto** const peers = (tr_peer**)tr_ptrArrayBase(&tor->swarm->peers);
for (int i = 0; i < peerCount; ++i)
for (auto* peer : tor->swarm->peers)
{
tr_peerUpdateProgress(tor, peers[i]);
tr_peerUpdateProgress(tor, peer);
}
/* update the bittorrent peers' willingness... */
for (int i = 0; i < peerCount; ++i)
for (auto* peer : tor->swarm->peers)
{
auto* msgs = static_cast<tr_peerMsgs*>(peers[i]);
msgs->update_active(TR_UP);
msgs->update_active(TR_DOWN);
peer->update_active(TR_UP);
peer->update_active(TR_DOWN);
}
}
@ -1565,8 +1544,7 @@ void tr_peerMgrTorrentAvailability(tr_torrent const* tor, int8_t* tab, unsigned
if (tor->hasMetainfo())
{
int const peerCount = tr_ptrArraySize(&tor->swarm->peers);
auto const** peers = (tr_peer const**)tr_ptrArrayBase(&tor->swarm->peers);
auto const& peers = tor->swarm->peers;
float const interval = tor->pieceCount() / (float)tabCount;
auto const isSeed = tor->isSeed();
@ -1578,15 +1556,12 @@ void tr_peerMgrTorrentAvailability(tr_torrent const* tor, int8_t* tab, unsigned
{
tab[i] = -1;
}
else if (peerCount != 0)
else
{
for (int j = 0; j < peerCount; ++j)
{
if (peers[j]->have.test(piece))
{
++tab[i];
}
}
tab[i] = std::count_if(
std::begin(peers),
std::end(peers),
[piece](auto const* peer) { return peer->have.test(piece); });
}
}
}
@ -1642,16 +1617,15 @@ uint64_t tr_peerMgrGetDesiredAvailable(tr_torrent const* tor)
return 0;
}
size_t const n_peers = tr_ptrArraySize(&s->peers);
auto const n_peers = s->peerCount();
if (n_peers == 0)
{
return 0;
}
auto const** const peers = (tr_peer const**)tr_ptrArrayBase(&s->peers);
for (size_t i = 0; i < n_peers; ++i)
for (auto const* const peer : s->peers)
{
if (peers[i]->atom != nullptr && atomIsSeed(peers[i]->atom))
if (peer->atom != nullptr && atomIsSeed(peer->atom))
{
return tor->leftUntilDone();
}
@ -1663,10 +1637,8 @@ uint64_t tr_peerMgrGetDesiredAvailable(tr_torrent const* tor)
auto const n_pieces = tor->pieceCount();
auto have = std::vector<bool>(n_pieces);
for (size_t i = 0; i < n_peers; ++i)
for (auto const* const peer : s->peers)
{
auto const* const peer = peers[i];
for (size_t j = 0; j < n_pieces; ++j)
{
if (peer->have.test(j))
@ -1793,23 +1765,23 @@ static auto getPeerStats(tr_peerMsgs const* peer, time_t now, uint64_t now_msec)
return stats;
}
struct tr_peer_stat* tr_peerMgrPeerStats(tr_torrent const* tor, int* setmeCount)
struct tr_peer_stat* tr_peerMgrPeerStats(tr_torrent const* tor, int* setme_count)
{
TR_ASSERT(tr_isTorrent(tor));
TR_ASSERT(tor->swarm->manager != nullptr);
auto** peers = (tr_peerMsgs**)tr_ptrArrayBase(&tor->swarm->peers);
int const size = tr_ptrArraySize(&tor->swarm->peers);
auto* const ret = tr_new0(tr_peer_stat, size);
auto const n = tor->swarm->peerCount();
auto* const ret = tr_new0(tr_peer_stat, n);
time_t const now = tr_time();
uint64_t const now_msec = tr_time_msec();
for (int i = 0; i < size; ++i)
{
ret[i] = getPeerStats(peers[i], now, now_msec);
}
std::transform(
std::begin(tor->swarm->peers),
std::end(tor->swarm->peers),
ret,
[&now, &now_msec](auto const* peer) { return getPeerStats(peer, now, now_msec); });
*setmeCount = size;
*setme_count = n;
return ret;
}
@ -1823,13 +1795,8 @@ void tr_peerMgrClearInterest(tr_torrent* tor)
TR_ASSERT(tr_isTorrent(tor));
auto const lock = tor->unique_lock();
tr_swarm* s = tor->swarm;
int const peerCount = tr_ptrArraySize(&s->peers);
for (int i = 0; i < peerCount; ++i)
{
static_cast<tr_peerMsgs*>(tr_ptrArrayNth(&s->peers, i))->set_interested(false);
}
auto& peers = tor->swarm->peers;
std::for_each(std::begin(peers), std::end(peers), [](auto* const peer) { peer->set_interested(false); });
}
/* does this peer have any pieces that we want? */
@ -1887,11 +1854,13 @@ static void rechokeDownloads(tr_swarm* s)
{
static auto constexpr MinInterestingPeers = uint16_t{ 5 };
auto const peerCount = s->peerCount();
auto const& peers = s->peers;
auto const now = tr_time();
uint16_t max_peers = 0;
uint16_t rechoke_count = 0;
struct tr_rechoke_info* rechoke = nullptr;
int const peerCount = tr_ptrArraySize(&s->peers);
time_t const now = tr_time();
/* some cases where this function isn't necessary */
if (s->tor->isDone() || !s->tor->clientCanDownload())
@ -1918,9 +1887,8 @@ static void rechokeDownloads(tr_swarm* s)
* peers in our calculations lest they confuse Transmission into
* thinking it's hit its bandwidth cap.
*/
for (int i = 0; i < peerCount; ++i)
for (auto const* const peer : peers)
{
auto const* const peer = static_cast<tr_peer const*>(tr_ptrArrayNth(&s->peers, i));
auto const b = peer->blocksSentToClient.count(now, CancelHistorySec);
if (b == 0) /* ignore unresponsive peers, as described above */
@ -1985,10 +1953,8 @@ static void rechokeDownloads(tr_swarm* s)
}
/* decide WHICH peers to be interested in (based on their cancel-to-block ratio) */
for (int i = 0; i < peerCount; ++i)
for (auto* const peer : peers)
{
auto* const peer = static_cast<tr_peerMsgs*>(tr_ptrArrayNth(&s->peers, i));
if (!isPeerInteresting(s->tor, piece_is_interesting, peer))
{
peer->set_interested(false);
@ -2139,10 +2105,10 @@ static void rechokeUploads(tr_swarm* s, uint64_t const now)
{
auto const lock = s->manager->unique_lock();
int const peerCount = tr_ptrArraySize(&s->peers);
auto** peers = (tr_peerMsgs**)tr_ptrArrayBase(&s->peers);
auto const peerCount = s->peerCount();
auto& peers = s->peers;
auto* const choke = tr_new0(struct ChokeData, peerCount);
tr_session const* session = s->manager->session;
auto const* const session = s->manager->session;
bool const chokeAll = !s->tor->clientCanUpload();
bool const isMaxedOut = isBandwidthMaxedOut(s->tor->bandwidth_, now, TR_UP);
@ -2160,9 +2126,8 @@ static void rechokeUploads(tr_swarm* s, uint64_t const now)
int size = 0;
/* sort the peers by preference and rate */
for (int i = 0; i < peerCount; ++i)
for (auto* const peer : peers)
{
auto* const peer = peers[i];
peer_atom const* const atom = peer->atom;
if (tr_peerIsSeed(peer))
@ -2402,11 +2367,15 @@ static void removePeer(tr_peer* peer)
atom->time = tr_time();
tr_ptrArrayRemoveSortedPointer(&s->peers, peer, peerCompare);
if (auto iter = std::find(std::begin(s->peers), std::end(s->peers), peer); iter != std::end(s->peers))
{
s->peers.erase(iter);
}
--s->stats.peer_count;
--s->stats.peer_from_count[atom->fromFirst];
TR_ASSERT(s->stats.peer_count == tr_ptrArraySize(&s->peers));
TR_ASSERT(s->stats.peer_count == s->peerCount());
TR_ASSERT(s->stats.peer_from_count[atom->fromFirst] >= 0);
delete peer;
@ -2437,27 +2406,25 @@ static void closePeer(tr_peer* peer)
static void removeAllPeers(tr_swarm* swarm)
{
size_t const n = tr_ptrArraySize(&swarm->peers);
auto** base = (tr_peer**)tr_ptrArrayBase(&swarm->peers);
for (auto* peer : std::vector<tr_peer*>{ base, base + n })
{
removePeer(peer);
}
auto tmp = swarm->peers;
std::for_each(std::begin(tmp), std::end(tmp), removePeer);
TR_ASSERT(swarm->stats.peer_count == 0);
}
static auto getPeersToClose(tr_swarm* s, time_t const now_sec)
static auto getPeersToClose(tr_swarm* swarm, time_t const now_sec)
{
auto peerCount = int{};
auto** const peers = (tr_peer**)tr_ptrArrayPeek(&s->peers, &peerCount);
auto peers_to_close = std::vector<tr_peer*>{};
auto test = [=](auto* peer)
auto const peer_count = swarm->peerCount();
for (auto* peer : swarm->peers)
{
return shouldPeerBeClosed(s, peer, peerCount, now_sec);
};
std::copy_if(peers, peers + peerCount, std::back_inserter(peers_to_close), test);
if (shouldPeerBeClosed(swarm, peer, peer_count, now_sec))
{
peers_to_close.push_back(peer);
}
}
return peers_to_close;
}
@ -2501,21 +2468,18 @@ struct ComparePeerByActivity
}
};
static void enforceTorrentPeerLimit(tr_swarm* s)
static void enforceTorrentPeerLimit(tr_swarm* swarm)
{
// do we have too many peers?
int n = tr_ptrArraySize(&s->peers);
int const max = tr_torrentGetPeerLimit(s->tor);
auto const n = swarm->peerCount();
auto const max = tr_torrentGetPeerLimit(swarm->tor);
if (n <= max)
{
return;
}
// close all but the `max` most active
auto peers = std::vector<tr_peer*>{};
peers.reserve(n);
auto** base = (tr_peer**)tr_ptrArrayBase(&s->peers);
std::copy_n(base, n, std::back_inserter(peers));
auto peers = swarm->peers;
std::partial_sort(std::begin(peers), std::begin(peers) + max, std::end(peers), ComparePeerByActivity{});
std::for_each(std::begin(peers) + max, std::end(peers), closePeer);
}
@ -2528,7 +2492,7 @@ static void enforceSessionPeerLimit(tr_session* session)
std::begin(torrents),
std::end(torrents),
size_t{},
[](size_t sum, tr_torrent const* tor) { return sum + tr_ptrArraySize(&tor->swarm->peers); });
[](size_t sum, tr_torrent const* tor) { return sum + tor->swarm->peerCount(); });
size_t const max = tr_sessionGetPeerLimit(session);
if (n_peers <= max)
{
@ -2540,9 +2504,7 @@ static void enforceSessionPeerLimit(tr_session* session)
peers.reserve(n_peers);
for (auto const* const tor : session->torrents())
{
size_t const n = tr_ptrArraySize(&tor->swarm->peers);
auto** base = (tr_peer**)tr_ptrArrayBase(&tor->swarm->peers);
std::copy_n(base, n, std::back_inserter(peers));
peers.insert(std::end(peers), std::begin(tor->swarm->peers), std::end(tor->swarm->peers));
}
// close all but the `max` most active
@ -2597,11 +2559,9 @@ static void pumpAllPeers(tr_peerMgr* mgr)
{
for (auto* const tor : mgr->session->torrents())
{
tr_swarm* s = tor->swarm;
for (int j = 0, n = tr_ptrArraySize(&s->peers); j < n; ++j)
for (auto* const peer : tor->swarm->peers)
{
static_cast<tr_peerMsgs*>(tr_ptrArrayNth(&s->peers, j))->pulse();
peer->pulse();
}
}
}
@ -2965,15 +2925,15 @@ static std::vector<peer_candidate> getPeerCandidates(tr_session* session, size_t
time_t const now = tr_time();
uint64_t const now_msec = tr_time_msec();
/* leave 5% of connection slots for incoming connections -- ticket #2609 */
int const maxCandidates = tr_sessionGetPeerLimit(session) * 0.95;
size_t const maxCandidates = tr_sessionGetPeerLimit(session) * 0.95;
/* count how many peers and atoms we've got */
int atomCount = 0;
int peerCount = 0;
size_t peerCount = 0;
for (auto const* tor : session->torrents())
{
atomCount += tr_ptrArraySize(&tor->swarm->pool);
peerCount += tr_ptrArraySize(&tor->swarm->peers);
peerCount += tor->swarm->peerCount();
}
/* don't start any new handshakes if we're full up */
@ -3002,7 +2962,7 @@ static std::vector<peer_candidate> getPeerCandidates(tr_session* session, size_t
}
/* if we've already got enough peers in this torrent... */
if (tr_torrentGetPeerLimit(tor) <= tr_ptrArraySize(&tor->swarm->peers))
if (tr_torrentGetPeerLimit(tor) <= tor->swarm->peerCount())
{
continue;
}