mirror of
https://github.com/transmission/transmission.git
synced 2025-12-20 02:18:42 +00:00
refactor: avoid evbuffer use in tr_web, tr_webseed (#7743)
* refactor: add Task::add_data() * refactor: move response body preallocation to Task ctor * refactor: make Task::body() private * refactor: add FetchOptions::on_data_received callback * refactor: remove FetchOptions::buffer * refactor: remove evbuffer from web.cc * refactor: remove evbuffer from webseed.cc * refactor: remove unused evbuffer_unique_ptr * fix: copypaste error Xref: https://github.com/transmission/transmission/pull/7743\#discussion_r2516592222
This commit is contained in:
@@ -3,7 +3,6 @@
|
|||||||
// or any future license endorsed by Mnemosyne LLC.
|
// or any future license endorsed by Mnemosyne LLC.
|
||||||
// License text can be found in the licenses/ folder.
|
// License text can be found in the licenses/ folder.
|
||||||
|
|
||||||
#include <event2/buffer.h>
|
|
||||||
#include <event2/event.h>
|
#include <event2/event.h>
|
||||||
#include <event2/http.h>
|
#include <event2/http.h>
|
||||||
|
|
||||||
@@ -12,14 +11,6 @@
|
|||||||
namespace libtransmission::evhelpers
|
namespace libtransmission::evhelpers
|
||||||
{
|
{
|
||||||
|
|
||||||
void BufferDeleter::operator()(struct evbuffer* buf) const noexcept
|
|
||||||
{
|
|
||||||
if (buf != nullptr)
|
|
||||||
{
|
|
||||||
evbuffer_free(buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EventBaseDeleter::operator()(struct event_base* evbase) const noexcept
|
void EventBaseDeleter::operator()(struct event_base* evbase) const noexcept
|
||||||
{
|
{
|
||||||
if (evbase != nullptr)
|
if (evbase != nullptr)
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
struct evbuffer;
|
|
||||||
struct event;
|
struct event;
|
||||||
struct event_base;
|
struct event_base;
|
||||||
struct evhttp;
|
struct evhttp;
|
||||||
@@ -19,13 +18,6 @@ struct evhttp;
|
|||||||
namespace libtransmission::evhelpers
|
namespace libtransmission::evhelpers
|
||||||
{
|
{
|
||||||
|
|
||||||
struct BufferDeleter
|
|
||||||
{
|
|
||||||
void operator()(struct evbuffer* buf) const noexcept;
|
|
||||||
};
|
|
||||||
|
|
||||||
using evbuffer_unique_ptr = std::unique_ptr<struct evbuffer, BufferDeleter>;
|
|
||||||
|
|
||||||
struct EventBaseDeleter
|
struct EventBaseDeleter
|
||||||
{
|
{
|
||||||
void operator()(struct event_base* evbase) const noexcept;
|
void operator()(struct event_base* evbase) const noexcept;
|
||||||
|
|||||||
@@ -33,8 +33,6 @@
|
|||||||
|
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
|
|
||||||
#include <event2/buffer.h>
|
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@@ -42,7 +40,6 @@
|
|||||||
#endif
|
#endif
|
||||||
#include "libtransmission/log.h"
|
#include "libtransmission/log.h"
|
||||||
#include "libtransmission/tr-assert.h"
|
#include "libtransmission/tr-assert.h"
|
||||||
#include "libtransmission/utils-ev.h"
|
|
||||||
#include "libtransmission/utils.h"
|
#include "libtransmission/utils.h"
|
||||||
#include "libtransmission/web.h"
|
#include "libtransmission/web.h"
|
||||||
#include "libtransmission/web-utils.h"
|
#include "libtransmission/web-utils.h"
|
||||||
@@ -264,6 +261,13 @@ public:
|
|||||||
easy_ = parsed ? impl.get_easy(parsed->host) : nullptr;
|
easy_ = parsed ? impl.get_easy(parsed->host) : nullptr;
|
||||||
|
|
||||||
response.user_data = options_.done_func_user_data;
|
response.user_data = options_.done_func_user_data;
|
||||||
|
|
||||||
|
if (options_.range)
|
||||||
|
{
|
||||||
|
// preallocate the response body buffer
|
||||||
|
auto const& [first, last] = *options_.range;
|
||||||
|
response.body.reserve(last + 1U - first);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some of the curl_easy_setopt() args took a pointer to this task.
|
// Some of the curl_easy_setopt() args took a pointer to this task.
|
||||||
@@ -283,11 +287,6 @@ public:
|
|||||||
return easy_;
|
return easy_;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto* body() const
|
|
||||||
{
|
|
||||||
return options_.buffer != nullptr ? options_.buffer : privbuf_.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr auto const& speedLimitTag() const
|
[[nodiscard]] constexpr auto const& speedLimitTag() const
|
||||||
{
|
{
|
||||||
return options_.speed_limit_tag;
|
return options_.speed_limit_tag;
|
||||||
@@ -355,6 +354,17 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void add_data(void const* data, size_t const n_bytes)
|
||||||
|
{
|
||||||
|
response.body.append(static_cast<char const*>(data), n_bytes);
|
||||||
|
tr_logAddTrace(fmt::format("wrote {} bytes to task {}'s buffer", n_bytes, fmt::ptr(this)));
|
||||||
|
|
||||||
|
if (options_.on_data_received)
|
||||||
|
{
|
||||||
|
options_.on_data_received(n_bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void done()
|
void done()
|
||||||
{
|
{
|
||||||
if (!options_.done_func)
|
if (!options_.done_func)
|
||||||
@@ -362,7 +372,6 @@ public:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
response.body.assign(reinterpret_cast<char const*>(evbuffer_pullup(body(), -1)), evbuffer_get_length(body()));
|
|
||||||
impl.mediator.run(std::move(options_.done_func), std::move(this->response));
|
impl.mediator.run(std::move(options_.done_func), std::move(this->response));
|
||||||
options_.done_func = {};
|
options_.done_func = {};
|
||||||
}
|
}
|
||||||
@@ -396,8 +405,6 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
libtransmission::evhelpers::evbuffer_unique_ptr privbuf_{ evbuffer_new() };
|
|
||||||
|
|
||||||
tr_web::FetchOptions options_;
|
tr_web::FetchOptions options_;
|
||||||
|
|
||||||
CURL* easy_;
|
CURL* easy_;
|
||||||
@@ -522,8 +529,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
evbuffer_add(task->body(), data, bytes_used);
|
task->add_data(data, bytes_used);
|
||||||
tr_logAddTrace(fmt::format("wrote {} bytes to task {}'s buffer", bytes_used, fmt::ptr(task)));
|
|
||||||
return bytes_used;
|
return bytes_used;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -641,12 +647,9 @@ public:
|
|||||||
(void)curl_easy_setopt(e, CURLOPT_HTTP_CONTENT_DECODING, 0L);
|
(void)curl_easy_setopt(e, CURLOPT_HTTP_CONTENT_DECODING, 0L);
|
||||||
|
|
||||||
// set the range request
|
// set the range request
|
||||||
auto const [first, last] = *range;
|
auto const& [first, last] = *range;
|
||||||
auto const range_str = fmt::format("{:d}-{:d}", first, last);
|
auto const str = fmt::format("{:d}-{:d}", first, last);
|
||||||
(void)curl_easy_setopt(e, CURLOPT_RANGE, range_str.c_str());
|
(void)curl_easy_setopt(e, CURLOPT_RANGE, str.c_str());
|
||||||
|
|
||||||
// preallocate the response body buffer
|
|
||||||
evbuffer_expand(task.body(), last + 1U - first);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curl_avoid_http2)
|
if (curl_avoid_http2)
|
||||||
|
|||||||
@@ -16,8 +16,6 @@
|
|||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
struct evbuffer;
|
|
||||||
|
|
||||||
class tr_web
|
class tr_web
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -85,10 +83,9 @@ public:
|
|||||||
// Maximum time to wait before timeout
|
// Maximum time to wait before timeout
|
||||||
std::chrono::seconds timeout_secs = DefaultTimeoutSecs;
|
std::chrono::seconds timeout_secs = DefaultTimeoutSecs;
|
||||||
|
|
||||||
// If provided, this buffer will be used to hold the response body.
|
// Called periodically by the web internals when data is received.
|
||||||
// Provided for webseeds, which need to set low-level callbacks on
|
// Used by webseeds to report to tr_bandwidth for data xfer stats
|
||||||
// the buffer itself.
|
std::function<void(size_t /*n_bytes*/)> on_data_received;
|
||||||
evbuffer* buffer = nullptr;
|
|
||||||
|
|
||||||
// IP protocol to use when making the request
|
// IP protocol to use when making the request
|
||||||
IPProtocol ip_proto = IPProtocol::ANY;
|
IPProtocol ip_proto = IPProtocol::ANY;
|
||||||
|
|||||||
@@ -14,8 +14,6 @@
|
|||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include <event2/buffer.h>
|
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include "libtransmission/transmission.h"
|
#include "libtransmission/transmission.h"
|
||||||
@@ -30,16 +28,14 @@
|
|||||||
#include "libtransmission/timer.h"
|
#include "libtransmission/timer.h"
|
||||||
#include "libtransmission/torrent.h"
|
#include "libtransmission/torrent.h"
|
||||||
#include "libtransmission/tr-assert.h"
|
#include "libtransmission/tr-assert.h"
|
||||||
|
#include "libtransmission/tr-buffer.h"
|
||||||
#include "libtransmission/tr-macros.h"
|
#include "libtransmission/tr-macros.h"
|
||||||
#include "libtransmission/tr-strbuf.h"
|
#include "libtransmission/tr-strbuf.h"
|
||||||
#include "libtransmission/utils-ev.h"
|
|
||||||
#include "libtransmission/utils.h"
|
#include "libtransmission/utils.h"
|
||||||
#include "libtransmission/web-utils.h"
|
#include "libtransmission/web-utils.h"
|
||||||
#include "libtransmission/web.h"
|
#include "libtransmission/web.h"
|
||||||
#include "libtransmission/webseed.h"
|
#include "libtransmission/webseed.h"
|
||||||
|
|
||||||
struct evbuffer;
|
|
||||||
|
|
||||||
using namespace std::literals;
|
using namespace std::literals;
|
||||||
using namespace libtransmission::Values;
|
using namespace libtransmission::Values;
|
||||||
|
|
||||||
@@ -57,12 +53,6 @@ public:
|
|||||||
, end_byte_{ tor.block_loc(blocks.end - 1).byte + tor.block_size(blocks.end - 1) }
|
, end_byte_{ tor.block_loc(blocks.end - 1).byte + tor.block_size(blocks.end - 1) }
|
||||||
, loc_{ tor.block_loc(blocks.begin) }
|
, loc_{ tor.block_loc(blocks.begin) }
|
||||||
{
|
{
|
||||||
evbuffer_add_cb(content_.get(), on_buffer_got_data, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto* content() const
|
|
||||||
{
|
|
||||||
return content_.get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void request_next_chunk();
|
void request_next_chunk();
|
||||||
@@ -74,7 +64,7 @@ private:
|
|||||||
void use_fetched_blocks();
|
void use_fetched_blocks();
|
||||||
|
|
||||||
static void on_partial_data_fetched(tr_web::FetchResponse const& web_response);
|
static void on_partial_data_fetched(tr_web::FetchResponse const& web_response);
|
||||||
static void on_buffer_got_data(evbuffer* /*buf*/, evbuffer_cb_info const* info, void* vtask);
|
void on_data_received(size_t n_bytes);
|
||||||
|
|
||||||
tr_webseed_impl* const webseed_;
|
tr_webseed_impl* const webseed_;
|
||||||
tr_session* const session_;
|
tr_session* const session_;
|
||||||
@@ -83,7 +73,7 @@ private:
|
|||||||
// the current position in the task; i.e., the next block to save
|
// the current position in the task; i.e., the next block to save
|
||||||
tr_block_info::Location loc_;
|
tr_block_info::Location loc_;
|
||||||
|
|
||||||
libtransmission::evhelpers::evbuffer_unique_ptr const content_{ evbuffer_new() };
|
libtransmission::StackBuffer<tr_block_info::BlockSize, std::byte, std::ratio<5, 1>> content_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -377,22 +367,22 @@ void tr_webseed_task::use_fetched_blocks()
|
|||||||
|
|
||||||
auto const& tor = webseed_->tor;
|
auto const& tor = webseed_->tor;
|
||||||
|
|
||||||
for (auto* const buf = content();;)
|
for (;;)
|
||||||
{
|
{
|
||||||
auto const block_size = tor.block_size(loc_.block);
|
auto const block_size = tor.block_size(loc_.block);
|
||||||
if (evbuffer_get_length(buf) < block_size)
|
if (std::size(content_) < block_size)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tor.has_block(loc_.block))
|
if (tor.has_block(loc_.block))
|
||||||
{
|
{
|
||||||
evbuffer_drain(buf, block_size);
|
content_.drain(block_size);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto block_buf = new Cache::BlockData(block_size);
|
auto block_buf = new Cache::BlockData(block_size);
|
||||||
evbuffer_remove(buf, std::data(*block_buf), std::size(*block_buf));
|
content_.to_buf(std::data(*block_buf), std::size(*block_buf));
|
||||||
session_->run_in_session_thread(
|
session_->run_in_session_thread(
|
||||||
[session = session_, tor_id = tor.id(), block = loc_.block, block_buf, webseed = webseed_]()
|
[session = session_, tor_id = tor.id(), block = loc_.block, block_buf, webseed = webseed_]()
|
||||||
{
|
{
|
||||||
@@ -415,17 +405,15 @@ void tr_webseed_task::use_fetched_blocks()
|
|||||||
|
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
void tr_webseed_task::on_buffer_got_data(evbuffer* /*buf*/, evbuffer_cb_info const* info, void* vtask)
|
void tr_webseed_task::on_data_received(size_t const n_bytes)
|
||||||
{
|
{
|
||||||
size_t const n_added = info->n_added;
|
if (n_bytes == 0 || dead)
|
||||||
auto* const task = static_cast<tr_webseed_task*>(vtask);
|
|
||||||
if (n_added == 0 || task->dead)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const lock = task->session_->unique_lock();
|
auto const lock = session_->unique_lock();
|
||||||
task->webseed_->got_piece_data(n_added);
|
webseed_->got_piece_data(n_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tr_webseed_task::on_partial_data_fetched(tr_web::FetchResponse const& web_response)
|
void tr_webseed_task::on_partial_data_fetched(tr_web::FetchResponse const& web_response)
|
||||||
@@ -452,6 +440,7 @@ void tr_webseed_task::on_partial_data_fetched(tr_web::FetchResponse const& web_r
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task->content_.add(std::data(body), std::size(body));
|
||||||
task->use_fetched_blocks();
|
task->use_fetched_blocks();
|
||||||
|
|
||||||
if (task->loc_.byte < task->end_byte_)
|
if (task->loc_.byte < task->end_byte_)
|
||||||
@@ -463,7 +452,7 @@ void tr_webseed_task::on_partial_data_fetched(tr_web::FetchResponse const& web_r
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TR_ASSERT(evbuffer_get_length(task->content()) == 0);
|
TR_ASSERT(std::empty(task->content_));
|
||||||
TR_ASSERT(task->loc_.byte == task->end_byte_);
|
TR_ASSERT(task->loc_.byte == task->end_byte_);
|
||||||
webseed->tasks.erase(task);
|
webseed->tasks.erase(task);
|
||||||
delete task;
|
delete task;
|
||||||
@@ -488,7 +477,7 @@ void tr_webseed_task::request_next_chunk()
|
|||||||
{
|
{
|
||||||
auto const& tor = webseed_->tor;
|
auto const& tor = webseed_->tor;
|
||||||
|
|
||||||
auto const downloaded_loc = tor.byte_loc(loc_.byte + evbuffer_get_length(content()));
|
auto const downloaded_loc = tor.byte_loc(loc_.byte + std::size(content_));
|
||||||
|
|
||||||
auto const [file_index, file_offset] = tor.file_offset(downloaded_loc);
|
auto const [file_index, file_offset] = tor.file_offset(downloaded_loc);
|
||||||
auto const left_in_file = tor.file_size(file_index) - file_offset;
|
auto const left_in_file = tor.file_size(file_index) - file_offset;
|
||||||
@@ -503,7 +492,10 @@ void tr_webseed_task::request_next_chunk()
|
|||||||
auto options = tr_web::FetchOptions{ url.sv(), on_partial_data_fetched, this };
|
auto options = tr_web::FetchOptions{ url.sv(), on_partial_data_fetched, this };
|
||||||
options.range.emplace(file_offset, file_offset + this_chunk - 1);
|
options.range.emplace(file_offset, file_offset + this_chunk - 1);
|
||||||
options.speed_limit_tag = tor.id();
|
options.speed_limit_tag = tor.id();
|
||||||
options.buffer = content();
|
options.on_data_received = [this](size_t const n_bytes)
|
||||||
|
{
|
||||||
|
on_data_received(n_bytes);
|
||||||
|
};
|
||||||
tor.session->fetch(std::move(options));
|
tor.session->fetch(std::move(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user