refactor: add tr_peer.canRequest() (#3408)

This commit is contained in:
Charles Kerr 2022-07-04 13:03:32 -05:00 committed by GitHub
parent 513f4bc91b
commit 9dfb3bf3df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 79 additions and 46 deletions

View File

@ -89,6 +89,19 @@ public:
virtual void requestBlocks(tr_block_span_t const* block_spans, size_t n_spans) = 0;
struct RequestLimit
{
// How many blocks we could request.
size_t max_spans = 0;
// How many spans those blocks could be in.
// This is for webseeds, which make parallel requests.
size_t max_blocks = 0;
};
// how many blocks could we request from this peer right now?
[[nodiscard]] virtual RequestLimit canRequest() const noexcept = 0;
tr_session* const session;
tr_swarm* const swarm;

View File

@ -658,7 +658,47 @@ public:
}
}
// how many blocks could we request from this peer right now?
[[nodiscard]] RequestLimit canRequest() const noexcept override
{
auto const max_blocks = maxAvailableReqs();
return RequestLimit{ max_blocks, max_blocks };
}
private:
[[nodiscard]] size_t maxAvailableReqs() const
{
if (torrent->isDone() || !torrent->hasMetainfo() || client_is_choked_ || !client_is_interested_)
{
return 0;
}
// Get the rate limit we should use.
// TODO: this needs to consider all the other peers as well...
uint64_t const now = tr_time_msec();
auto rate_Bps = tr_peerGetPieceSpeed_Bps(this, now, TR_PEER_TO_CLIENT);
if (tr_torrentUsesSpeedLimit(torrent, TR_PEER_TO_CLIENT))
{
rate_Bps = std::min(rate_Bps, torrent->speedLimitBps(TR_PEER_TO_CLIENT));
}
// honor the session limits, if enabled
auto irate_Bps = unsigned{};
if (tr_torrentUsesSessionLimits(torrent) &&
tr_sessionGetActiveSpeedLimit_Bps(torrent->session, TR_PEER_TO_CLIENT, &irate_Bps))
{
rate_Bps = std::min(rate_Bps, irate_Bps);
}
// use this desired rate to figure out how
// many requests we should send to this peer
size_t constexpr Floor = 32;
size_t constexpr Seconds = RequestBufSecs;
size_t const estimated_blocks_in_period = (rate_Bps * Seconds) / tr_block_info::BlockSize;
size_t const ceil = reqq ? *reqq : 250;
return std::clamp(estimated_blocks_in_period, Floor, ceil);
}
void protocolSendRequest(struct peer_request const& req)
{
TR_ASSERT(isValidRequest(req));
@ -2088,40 +2128,7 @@ static ReadState canRead(tr_peerIo* io, void* vmsgs, size_t* piece)
static void updateDesiredRequestCount(tr_peerMsgsImpl* msgs)
{
tr_torrent const* const torrent = msgs->torrent;
/* there are lots of reasons we might not want to request any blocks... */
if (torrent->isDone() || !torrent->hasMetainfo() || msgs->client_is_choked_ || !msgs->client_is_interested_)
{
msgs->desired_request_count = 0;
}
else
{
/* Get the rate limit we should use.
* TODO: this needs to consider all the other peers as well... */
uint64_t const now = tr_time_msec();
auto rate_Bps = tr_peerGetPieceSpeed_Bps(msgs, now, TR_PEER_TO_CLIENT);
if (tr_torrentUsesSpeedLimit(torrent, TR_PEER_TO_CLIENT))
{
rate_Bps = std::min(rate_Bps, torrent->speedLimitBps(TR_PEER_TO_CLIENT));
}
/* honor the session limits, if enabled */
auto irate_Bps = unsigned{};
if (tr_torrentUsesSessionLimits(torrent) &&
tr_sessionGetActiveSpeedLimit_Bps(torrent->session, TR_PEER_TO_CLIENT, &irate_Bps))
{
rate_Bps = std::min(rate_Bps, irate_Bps);
}
/* use this desired rate to figure out how
* many requests we should send to this peer */
size_t constexpr Floor = 32;
size_t constexpr Seconds = RequestBufSecs;
size_t const estimated_blocks_in_period = (rate_Bps * Seconds) / tr_block_info::BlockSize;
size_t const ceil = msgs->reqq ? *msgs->reqq : 250;
msgs->desired_request_count = std::clamp(estimated_blocks_in_period, Floor, ceil);
}
msgs->desired_request_count = msgs->canRequest().max_blocks;
}
static void updateMetadataRequests(tr_peerMsgsImpl* msgs, time_t now)

View File

@ -290,6 +290,26 @@ public:
}
}
[[nodiscard]] RequestLimit canRequest() const noexcept override
{
auto const n_slots = connection_limiter.slotsAvailable();
if (n_slots == 0)
{
return {};
}
if (auto* const tor = getTorrent(); tor == nullptr || !tor->isRunning || tor->isDone())
{
return {};
}
// Prefer to request large, contiguous chunks from webseeds.
// The actual value of '64' is arbitrary here;
// we could probably be smarter about this.
auto constexpr PreferredBlocksPerTask = size_t{ 64 };
return { n_slots, n_slots * PreferredBlocksPerTask };
}
tr_torrent_id_t const torrent_id;
std::string const base_url;
tr_peer_callback const callback;
@ -435,14 +455,8 @@ void onBufferGotData(evbuffer* /*buf*/, evbuffer_cb_info const* info, void* vtas
void on_idle(tr_webseed* webseed)
{
auto const slots_available = webseed->connection_limiter.slotsAvailable();
if (slots_available == 0)
{
return;
}
auto* const tor = webseed->getTorrent();
if (tor == nullptr || !tor->isRunning || tor->isDone())
auto const [max_spans, max_blocks] = webseed->canRequest();
if (max_spans == 0 || max_blocks == 0)
{
return;
}
@ -450,11 +464,10 @@ void on_idle(tr_webseed* webseed)
// Prefer to request large, contiguous chunks from webseeds.
// The actual value of '64' is arbitrary here; we could probably
// be smarter about this.
auto constexpr PreferredBlocksPerTask = size_t{ 64 };
auto spans = tr_peerMgrGetNextRequests(tor, webseed, slots_available * PreferredBlocksPerTask);
if (std::size(spans) > slots_available)
auto spans = tr_peerMgrGetNextRequests(webseed->getTorrent(), webseed, max_blocks);
if (std::size(spans) > max_spans)
{
spans.resize(slots_available);
spans.resize(max_spans);
}
webseed->requestBlocks(std::data(spans), std::size(spans));
}