1
0
Fork 0
mirror of https://github.com/transmission/transmission synced 2024-12-28 10:38:45 +00:00
transmission/libtransmission/peer-mgr-wishlist.cc
Charles Kerr f6f0db75e1
fix: sonarcloud warnings / code smells (#2242)
* fix: use-init-statement

Xref: https://sonarcloud.io/project/issues\?id\=transmission_transmission\&issues\=AX1f6EvHJiycnfA7gfrG\&open\=AX1f6EvHJiycnfA7gfrG

* fix replace-use-of-new warning

Xref: https://sonarcloud.io/project/issues\?id\=transmission_transmission\&issues\=AX1ZNs41ZmlvCveKTzon\&open\=AX1ZNs41ZmlvCveKTzon

* fix has-virtual-functions-but-non-virtual-destructor warning

Xref: https://sonarcloud.io/project/issues\?id\=transmission_transmission\&issues\=AX1ZNs72ZmlvCveKTzo6\&open\=AX1ZNs72ZmlvCveKTzo6

* fix make-variable-const warning

Xref: https://sonarcloud.io/project/issues\?id\=transmission_transmission\&issues\=AX0_a_OVNJn7rAzml_7B\&open\=AX0_a_OVNJn7rAzml_7B

* fix remove-redundant-static-specifiers

Xref: https://sonarcloud.io/project/issues\?id\=transmission_transmission\&issues\=AX06St-81usi2gyYkPTb\&open\=AX06St-81usi2gyYkPTb

* fix function-should-be-declared-const

Xref: https://sonarcloud.io/project/issues\?id\=transmission_transmission\&issues\=AX06St-81usi2gyYkPTd\&open\=AX06St-81usi2gyYkPTd

* fix use-init-statement warning

Xref: https://sonarcloud.io/project/issues\?id\=transmission_transmission\&issues\=AX06St-81usi2gyYkPTc\&open\=AX06St-81usi2gyYkPTc

* fix class-has-virtual-functions-but-non-virtual-destructor warning

Xref: https://sonarcloud.io/project/issues\?id\=transmission_transmission\&issues\=AX06Stz41usi2gyYkPTS\&open\=AX06Stz41usi2gyYkPTS

* fix remove-commented-out-code warning

Xref: https://sonarcloud.io/project/issues\?id\=transmission_transmission\&issues\=AX06St241usi2gyYkPTT\&open\=AX06St241usi2gyYkPTT

* fix remove-commented-out-code warning

Xref: https://sonarcloud.io/project/issues\?id\=transmission_transmission\&issues\=AX06St241usi2gyYkPTV\&open\=AX06St241usi2gyYkPTV

* fix has-virtual-functions-but-non-virtual-destructor warning

https://sonarcloud.io/project/issues\?id\=transmission_transmission\&issues\=AX06St241usi2gyYkPTW\&open\=AX06St241usi2gyYkPTW

* fix remove-commented-out-code warning

Xref: https://sonarcloud.io/project/issues\?id\=transmission_transmission\&issues\=AX06SuCA1usi2gyYkPTh\&open\=AX06SuCA1usi2gyYkPTh

* fix use-init-statement warning

Xref: https://sonarcloud.io/project/issues\?id\=transmission_transmission\&issues\=AX0rAQvnfJ-O-YIDS9xF\&open\=AX0rAQvnfJ-O-YIDS9xF

* fix use-init-statement warning

Xref: https://sonarcloud.io/project/issues\?id\=transmission_transmission\&issues\=AX0rAQvnfJ-O-YIDS9xG\&open\=AX0rAQvnfJ-O-YIDS9xG

* fix remove-redundant-access-specifier warning

Xref: https://sonarcloud.io/project/issues\?id\=transmission_transmission\&issues\=AX1ZNs5tZmlvCveKTzor\&open\=AX1ZNs5tZmlvCveKTzor

* fix use-init-statement warning

Xref: https://sonarcloud.io/project/issues\?id\=transmission_transmission\&issues\=AX01Itl7f_SST5i7BN1l\&open\=AX01Itl7f_SST5i7BN1l

* fix use-init-statement warning

Xref: https://sonarcloud.io/project/issues\?id\=transmission_transmission\&issues\=AX0wDijI2l89lDvp1C9P\&open\=AX0wDijI2l89lDvp1C9P

* fix use-automatically-managed-memory-instead-of-new warning

Xref: https://sonarcloud.io/project/issues\?id\=transmission_transmission\&issues\=AX1f6E6HJiycnfA7gfrI\&open\=AX1f6E6HJiycnfA7gfrI

* fix use-init-statement warning

Xref: https://sonarcloud.io/project/issues\?id\=transmission_transmission\&issues\=AX0l8vknEafnvRiIHUEv\&open\=AX0l8vknEafnvRiIHUEv

* fixup! fix has-virtual-functions-but-non-virtual-destructor warning
2021-11-27 19:58:35 -06:00

198 lines
5.2 KiB
C++

/*
* This file Copyright (C) 2021 Mnemosyne LLC
*
* It may be used under the GNU GPL versions 2 or 3
* or any future license endorsed by Mnemosyne LLC.
*
*/
#include <algorithm>
#include <cstddef>
#include <iterator>
#include <numeric>
#include <utility>
#include <vector>
#define LIBTRANSMISSION_PEER_MODULE
#include "transmission.h"
#include "crypto-utils.h" // tr_rand_buffer()
#include "peer-mgr-wishlist.h"
namespace
{
struct Candidate
{
tr_piece_index_t piece;
size_t n_blocks_missing;
tr_priority_t priority;
uint8_t salt;
Candidate(tr_piece_index_t piece_in, size_t missing_in, tr_priority_t priority_in, uint8_t salt_in)
: piece{ piece_in }
, n_blocks_missing{ missing_in }
, priority{ priority_in }
, salt{ salt_in }
{
}
int compare(Candidate const& that) const // <=>
{
// prefer pieces closer to completion
if (n_blocks_missing != that.n_blocks_missing)
{
return n_blocks_missing < that.n_blocks_missing ? -1 : 1;
}
// prefer higher priority
if (priority != that.priority)
{
return priority > that.priority ? -1 : 1;
}
if (salt != that.salt)
{
return salt < that.salt ? -1 : 1;
}
return 0;
}
bool operator<(Candidate const& that) const // less than
{
return compare(that) < 0;
}
};
std::vector<Candidate> getCandidates(Wishlist::PeerInfo const& peer_info)
{
// count up the pieces that we still want
auto wanted_pieces = std::vector<std::pair<tr_piece_index_t, size_t>>{};
auto const n_pieces = peer_info.countAllPieces();
wanted_pieces.reserve(n_pieces);
for (tr_piece_index_t i = 0; i < n_pieces; ++i)
{
if (!peer_info.clientCanRequestPiece(i))
{
continue;
}
size_t const n_missing = peer_info.countMissingBlocks(i);
if (n_missing == 0)
{
continue;
}
wanted_pieces.emplace_back(i, n_missing);
}
// transform them into candidates
auto const n = std::size(wanted_pieces);
auto saltbuf = std::vector<char>(n);
tr_rand_buffer(std::data(saltbuf), n);
auto candidates = std::vector<Candidate>{};
candidates.reserve(n);
for (size_t i = 0; i < n; ++i)
{
auto const [piece, n_missing] = wanted_pieces[i];
candidates.emplace_back(piece, n_missing, peer_info.priority(piece), saltbuf[i]);
}
return candidates;
}
std::vector<tr_block_span_t> makeSpans(tr_block_index_t const* sorted_blocks, size_t n_blocks)
{
if (n_blocks == 0)
{
return {};
}
auto spans = std::vector<tr_block_span_t>{};
auto cur = tr_block_span_t{ sorted_blocks[0], sorted_blocks[0] + 1 };
for (size_t i = 1; i < n_blocks; ++i)
{
if (cur.end == sorted_blocks[i])
{
++cur.end;
}
else
{
spans.push_back(cur);
cur = tr_block_span_t{ sorted_blocks[i], sorted_blocks[i] + 1 };
}
}
spans.push_back(cur);
return spans;
}
} // namespace
std::vector<tr_block_span_t> Wishlist::next(Wishlist::PeerInfo const& peer_info, size_t n_wanted_blocks) const
{
size_t n_blocks = 0;
auto spans = std::vector<tr_block_span_t>{};
// sanity clause
TR_ASSERT(n_wanted_blocks > 0);
// We usually won't need all the candidates until endgame, so don't
// waste cycles sorting all of them here. partial sort is enough.
auto candidates = getCandidates(peer_info);
auto constexpr MaxSortedPieces = size_t{ 30 };
auto const middle = std::min(std::size(candidates), MaxSortedPieces);
std::partial_sort(std::begin(candidates), std::begin(candidates) + middle, std::end(candidates));
for (auto const& candidate : candidates)
{
// do we have enough?
if (n_blocks >= n_wanted_blocks)
{
break;
}
// walk the blocks in this piece
auto const [begin, end] = peer_info.blockSpan(candidate.piece);
auto blocks = std::vector<tr_block_index_t>{};
blocks.reserve(end - begin);
for (tr_block_index_t block = begin; block < end && n_blocks + std::size(blocks) < n_wanted_blocks; ++block)
{
// don't request blocks we've already got
if (!peer_info.clientCanRequestBlock(block))
{
continue;
}
// don't request from too many peers
size_t const n_peers = peer_info.countActiveRequests(block);
if (size_t const max_peers = peer_info.isEndgame() ? 2 : 1; n_peers >= max_peers)
{
continue;
}
blocks.push_back(block);
}
if (std::empty(blocks))
{
continue;
}
// copy the spans into `spans`
auto const tmp = makeSpans(std::data(blocks), std::size(blocks));
std::copy(std::begin(tmp), std::end(tmp), std::back_inserter(spans));
n_blocks += std::accumulate(
std::begin(tmp),
std::end(tmp),
size_t{},
[](size_t sum, auto span) { return sum + span.end - span.begin; });
if (n_blocks >= n_wanted_blocks)
{
break;
}
}
return spans;
}