refactor: remove peer-mgr replication info (#2021)

* refactor: remove peer-mgr replication info

Co-authored-by: Mike Gelfand <mikedld@users.noreply.github.com>
This commit is contained in:
Charles Kerr 2021-10-25 10:29:19 -05:00 committed by GitHub
parent 81147a8fbb
commit a1c5a215bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 40 additions and 287 deletions

View File

@ -204,13 +204,6 @@ public:
int pieceCount = 0;
enum piece_sort_state pieceSortState = PIECES_UNSORTED;
/* An array of pieceCount items stating how many peers have each piece.
This is used to help us for downloading pieces "rarest first."
This may be nullptr if we don't have metainfo yet, or if we're not
downloading and don't care about rarity */
uint16_t* pieceReplication = nullptr;
size_t pieceReplicationSize = 0;
int interestedCount = 0;
int maxPeers = 0;
time_t lastCancel = 0;
@ -374,13 +367,13 @@ static int peerCompare(void const* va, void const* vb)
static struct peer_atom* getExistingAtom(tr_swarm const* cswarm, tr_address const* addr)
{
tr_swarm* swarm = (tr_swarm*)cswarm;
auto* swarm = const_cast<tr_swarm*>(cswarm);
return static_cast<struct peer_atom*>(tr_ptrArrayFindSorted(&swarm->pool, addr, comparePeerAtomToAddress));
}
static bool peerIsInUse(tr_swarm const* cs, struct peer_atom const* atom)
{
tr_swarm* s = (tr_swarm*)cs;
auto* s = const_cast<tr_swarm*>(cs);
TR_ASSERT(swarmIsLocked(s));
@ -388,46 +381,6 @@ static bool peerIsInUse(tr_swarm const* cs, struct peer_atom const* atom)
getExistingHandshake(&s->manager->incomingHandshakes, &atom->addr) != nullptr;
}
static constexpr bool replicationExists(tr_swarm const* s)
{
return s->pieceReplication != nullptr;
}
static void replicationFree(tr_swarm* s)
{
tr_free(s->pieceReplication);
s->pieceReplication = nullptr;
s->pieceReplicationSize = 0;
}
static void replicationNew(tr_swarm* s)
{
TR_ASSERT(!replicationExists(s));
tr_piece_index_t const piece_count = s->tor->info.pieceCount;
int const n = tr_ptrArraySize(&s->peers);
s->pieceReplicationSize = piece_count;
s->pieceReplication = tr_new0(uint16_t, piece_count);
for (tr_piece_index_t piece_i = 0; piece_i < piece_count; ++piece_i)
{
uint16_t r = 0;
for (int peer_i = 0; peer_i < n; ++peer_i)
{
auto const* const peer = static_cast<tr_peer const*>(tr_ptrArrayNth(&s->peers, peer_i));
if (peer->have.test(piece_i))
{
++r;
}
}
s->pieceReplication[piece_i] = r;
}
}
static void swarmFree(void* vs)
{
auto* s = static_cast<tr_swarm*>(vs);
@ -444,8 +397,6 @@ static void swarmFree(void* vs)
tr_ptrArrayDestruct(&s->peers, nullptr);
s->stats = {};
replicationFree(s);
tr_free(s->requests);
tr_free(s->pieces);
@ -823,17 +774,9 @@ static constexpr void invalidatePieceSorting(tr_swarm* s)
static tr_torrent const* weightTorrent;
static uint16_t const* weightReplication;
static void setComparePieceByWeightTorrent(tr_swarm* s)
{
if (!replicationExists(s))
{
replicationNew(s);
}
weightTorrent = s->tor;
weightReplication = s->pieceReplication;
}
/* we try to create a "weight" s.t. high-priority pieces come before others,
@ -843,7 +786,6 @@ static int comparePieceByWeight(void const* va, void const* vb)
auto const* const a = static_cast<struct weighted_piece const*>(va);
auto const* const b = static_cast<struct weighted_piece const*>(vb);
tr_torrent const* const tor = weightTorrent;
uint16_t const* const rep = weightReplication;
/* primary key: weight */
int missing = tr_torrentMissingBlocksInPiece(tor, a->index);
@ -852,58 +794,21 @@ static int comparePieceByWeight(void const* va, void const* vb)
missing = tr_torrentMissingBlocksInPiece(tor, b->index);
pending = b->requestCount;
int ib = missing > pending ? missing - pending : tor->blockCountInPiece + pending;
if (ia < ib)
if (ia != ib)
{
return -1;
}
if (ia > ib)
{
return 1;
return ia < ib ? -1 : 1;
}
/* secondary key: higher priorities go first */
ia = tor->info.pieces[a->index].priority;
ib = tor->info.pieces[b->index].priority;
if (ia > ib)
if (ia != ib)
{
return -1;
return ia > ib ? -1 : 1;
}
if (ia < ib)
{
return 1;
}
/* tertiary key: rarest first. */
ia = rep[a->index];
ib = rep[b->index];
if (ia < ib)
{
return -1;
}
if (ia > ib)
{
return 1;
}
/* quaternary key: random */
if (a->salt < b->salt)
{
return -1;
}
if (a->salt > b->salt)
{
return 1;
}
/* okay, they're equal */
return 0;
/* tertiary key: random */
return a->salt - b->salt;
}
static int comparePieceByIndex(void const* va, void const* vb)
@ -951,7 +856,6 @@ static void pieceListSort(tr_swarm* s, enum piece_sort_state state)
#if 1
#define assertWeightedPiecesAreSorted(t)
#define assertReplicationCountIsExact(t)
#else
@ -968,36 +872,6 @@ static void assertWeightedPiecesAreSorted(Torrent* t)
}
}
static void assertReplicationCountIsExact(Torrent* t)
{
/* This assert might fail due to errors of implementations in other
* clients. It happens when receiving duplicate bitfields/HaveAll/HaveNone
* from a client. If a such a behavior is noticed,
* a bug report should be filled to the faulty client. */
uint16_t const* rep = t->pieceReplication;
size_t const piece_count = t->pieceReplicationSize;
tr_peer const** peers = (tr_peer const**)tr_ptrArrayBase(&t->peers);
int const peer_count = tr_ptrArraySize(&t->peers);
TR_ASSERT(piece_count == t->tor->info.pieceCount);
for (size_t piece_i = 0; piece_i < piece_count; ++piece_i)
{
uint16_t r = 0;
for (int peer_i = 0; peer_i < peer_count; ++peer_i)
{
if (tr_bitsetHas(&peers[peer_i]->have, piece_i))
{
++r;
}
}
TR_ASSERT(rep[piece_i] == r);
}
}
#endif
static constexpr weighted_piece* pieceListLookup(tr_swarm* s, tr_piece_index_t index)
@ -1161,100 +1035,6 @@ static void pieceListRemoveRequest(tr_swarm* s, tr_block_index_t block)
}
}
/****
*****
***** Replication count (for rarest first policy)
*****
****/
/**
* Increase the replication count of this piece and sort it if the
* piece list is already sorted
*/
static void tr_incrReplicationOfPiece(tr_swarm* s, size_t const index)
{
TR_ASSERT(replicationExists(s));
TR_ASSERT(s->pieceReplicationSize == s->tor->info.pieceCount);
/* One more replication of this piece is present in the swarm */
++s->pieceReplication[index];
/* we only resort the piece if the list is already sorted */
if (s->pieceSortState == PIECES_SORTED_BY_WEIGHT)
{
pieceListResortPiece(s, pieceListLookup(s, index));
}
}
/**
* Increases the replication count of pieces present in the bitfield
*/
static void tr_incrReplicationFromBitfield(tr_swarm* s, tr_bitfield const* b)
{
TR_ASSERT(replicationExists(s));
uint16_t* rep = s->pieceReplication;
for (size_t i = 0, n = s->tor->info.pieceCount; i < n; ++i)
{
if (b->test(i))
{
++rep[i];
}
}
if (s->pieceSortState == PIECES_SORTED_BY_WEIGHT)
{
invalidatePieceSorting(s);
}
}
/**
* Increase the replication count of every piece
*/
static void tr_incrReplication(tr_swarm* s)
{
TR_ASSERT(replicationExists(s));
TR_ASSERT(s->pieceReplicationSize == s->tor->info.pieceCount);
for (size_t i = 0; i < s->pieceReplicationSize; ++i)
{
++s->pieceReplication[i];
}
}
/**
* Decrease the replication count of pieces present in the bitset.
*/
static void tr_decrReplicationFromBitfield(tr_swarm* s, tr_bitfield const* b)
{
TR_ASSERT(replicationExists(s));
TR_ASSERT(s->pieceReplicationSize == s->tor->info.pieceCount);
if (b->hasAll())
{
for (size_t i = 0; i < s->pieceReplicationSize; ++i)
{
--s->pieceReplication[i];
}
}
else if (!b->hasNone())
{
for (size_t i = 0; i < s->pieceReplicationSize; ++i)
{
if (b->test(i))
{
--s->pieceReplication[i];
}
}
if (s->pieceSortState == PIECES_SORTED_BY_WEIGHT)
{
invalidatePieceSorting(s);
}
}
}
/**
***
**/
@ -1294,7 +1074,6 @@ void tr_peerMgrGetNextRequests(
pieceListSort(s, PIECES_SORTED_BY_WEIGHT);
}
assertReplicationCountIsExact(s);
assertWeightedPiecesAreSorted(s);
updateEndgame(s);
@ -1708,36 +1487,10 @@ static void peerCallbackFunc(tr_peer* peer, tr_peer_event const* e, void* vs)
}
case TR_PEER_CLIENT_GOT_HAVE:
if (replicationExists(s))
{
tr_incrReplicationOfPiece(s, e->pieceIndex);
assertReplicationCountIsExact(s);
}
break;
case TR_PEER_CLIENT_GOT_HAVE_ALL:
if (replicationExists(s))
{
tr_incrReplication(s);
assertReplicationCountIsExact(s);
}
break;
case TR_PEER_CLIENT_GOT_HAVE_NONE:
/* noop */
break;
case TR_PEER_CLIENT_GOT_BITFIELD:
TR_ASSERT(e->bitfield != nullptr);
if (replicationExists(s))
{
tr_incrReplicationFromBitfield(s, e->bitfield);
assertReplicationCountIsExact(s);
}
/* noop */
break;
case TR_PEER_CLIENT_GOT_REJ:
@ -2424,7 +2177,6 @@ static void stopSwarm(tr_swarm* swarm)
{
swarm->isRunning = false;
replicationFree(swarm);
invalidatePieceSorting(swarm);
removeAllPeers(swarm);
@ -2489,10 +2241,9 @@ void tr_peerUpdateProgress(tr_torrent* tor, tr_peer* peer)
}
}
/* clamp the progress range */
peer->progress = std::clamp(peer->progress, 0.0F, 1.0F);
if (peer->atom != nullptr && peer->progress >= 1.0F)
if (peer->atom != nullptr && peer->progress >= 1.0f)
{
atomSetSeed(tor->swarm, peer->atom);
}
@ -2606,29 +2357,27 @@ uint64_t tr_peerMgrGetDesiredAvailable(tr_torrent const* tor)
{
TR_ASSERT(tr_isTorrent(tor));
/* common shortcuts... */
// common shortcuts...
if (!tor->isRunning || tor->isStopping || tr_torrentIsSeed(tor) || !tr_torrentHasMetadata(tor))
{
return 0;
}
tr_swarm const* s = tor->swarm;
tr_swarm const* const s = tor->swarm;
if (s == nullptr || !s->isRunning)
{
return 0;
}
size_t const peer_count = tr_ptrArraySize(&s->peers);
if (peer_count == 0)
size_t const n_peers = tr_ptrArraySize(&s->peers);
if (n_peers == 0)
{
return 0;
}
tr_peer const** const peers = (tr_peer const**)tr_ptrArrayBase(&s->peers);
for (size_t i = 0; i < peer_count; ++i)
for (size_t i = 0; i < n_peers; ++i)
{
if (peers[i]->atom != nullptr && atomIsSeed(peers[i]->atom))
{
@ -2636,34 +2385,43 @@ uint64_t tr_peerMgrGetDesiredAvailable(tr_torrent const* tor)
}
}
if (s->pieceReplication == nullptr || s->pieceReplicationSize == 0)
// do it the hard way
auto desired_available = uint64_t{};
auto const n_pieces = tor->info.pieceCount;
auto have = std::vector<bool>(n_pieces);
for (size_t i = 0; i < n_peers; ++i)
{
return 0;
}
/* do it the hard way */
uint64_t desiredAvailable = 0;
for (size_t i = 0, n = std::min(size_t{ tor->info.pieceCount }, s->pieceReplicationSize); i < n; ++i)
{
if (!tor->info.pieces[i].dnd && s->pieceReplication[i] > 0)
auto* peer = peers[i];
for (size_t j = 0; j < n_pieces; ++j)
{
desiredAvailable += tr_torrentMissingBytesInPiece(tor, i);
if (peer->have.test(j))
{
have[j] = true;
}
}
}
TR_ASSERT(desiredAvailable <= tor->info.totalSize);
return desiredAvailable;
for (size_t i = 0; i < n_pieces; ++i)
{
if (!tor->info.pieces[i].dnd && have.at(i))
{
desired_available += tr_torrentMissingBytesInPiece(tor, i);
}
}
TR_ASSERT(desired_available <= tor->info.totalSize);
return desired_available;
}
double* tr_peerMgrWebSpeeds_KBps(tr_torrent const* tor)
{
TR_ASSERT(tr_isTorrent(tor));
uint64_t const now = tr_time_msec();
auto const now = tr_time_msec();
tr_swarm* s = tor->swarm;
tr_swarm* const s = tor->swarm;
TR_ASSERT(s->manager != nullptr);
unsigned int n = tr_ptrArraySize(&s->webseeds);
@ -3419,11 +3177,6 @@ static void removePeer(tr_swarm* s, tr_peer* peer)
--s->stats.peerCount;
--s->stats.peerFromCount[atom->fromFirst];
if (replicationExists(s))
{
tr_decrReplicationFromBitfield(s, &peer->have);
}
TR_ASSERT(s->stats.peerCount == tr_ptrArraySize(&s->peers));
TR_ASSERT(s->stats.peerFromCount[atom->fromFirst] >= 0);