mirror of
https://github.com/transmission/transmission
synced 2025-03-04 10:38:13 +00:00
perf: avoid extra heap alloc in block cache (#5522)
This commit is contained in:
parent
69fc149f07
commit
8a1a6dba49
5 changed files with 58 additions and 18 deletions
|
@ -73,7 +73,8 @@ std::pair<Cache::CIter, Cache::CIter> Cache::find_contiguous(CIter const begin,
|
||||||
int Cache::write_contiguous(CIter const begin, CIter const end) const
|
int Cache::write_contiguous(CIter const begin, CIter const end) const
|
||||||
{
|
{
|
||||||
// The most common case without an extra data copy.
|
// The most common case without an extra data copy.
|
||||||
auto const* towrite = begin->buf.get();
|
auto const* out = std::data(*begin->buf);
|
||||||
|
auto outlen = std::size(*begin->buf);
|
||||||
|
|
||||||
// Contiguous area to join more than one block, if any.
|
// Contiguous area to join more than one block, if any.
|
||||||
auto buf = std::vector<uint8_t>{};
|
auto buf = std::vector<uint8_t>{};
|
||||||
|
@ -94,7 +95,8 @@ int Cache::write_contiguous(CIter const begin, CIter const end) const
|
||||||
buf.insert(std::end(buf), std::begin(*iter->buf), std::end(*iter->buf));
|
buf.insert(std::end(buf), std::begin(*iter->buf), std::end(*iter->buf));
|
||||||
}
|
}
|
||||||
TR_ASSERT(std::size(buf) == buflen);
|
TR_ASSERT(std::size(buf) == buflen);
|
||||||
towrite = &buf;
|
out = std::data(buf);
|
||||||
|
outlen = std::size(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// save it
|
// save it
|
||||||
|
@ -107,13 +109,13 @@ int Cache::write_contiguous(CIter const begin, CIter const end) const
|
||||||
|
|
||||||
auto const loc = tor->block_loc(block);
|
auto const loc = tor->block_loc(block);
|
||||||
|
|
||||||
if (auto const err = tr_ioWrite(tor, loc, std::size(*towrite), std::data(*towrite)); err != 0)
|
if (auto const err = tr_ioWrite(tor, loc, outlen, out); err != 0)
|
||||||
{
|
{
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
++disk_writes_;
|
++disk_writes_;
|
||||||
disk_write_bytes_ += std::size(*towrite);
|
disk_write_bytes_ += outlen;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,7 +143,7 @@ Cache::Cache(tr_torrents& torrents, int64_t max_bytes)
|
||||||
|
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
int Cache::write_block(tr_torrent_id_t tor_id, tr_block_index_t block, std::unique_ptr<std::vector<uint8_t>> writeme)
|
int Cache::write_block(tr_torrent_id_t tor_id, tr_block_index_t block, std::unique_ptr<BlockData> writeme)
|
||||||
{
|
{
|
||||||
auto const key = Key{ tor_id, block };
|
auto const key = Key{ tor_id, block };
|
||||||
auto iter = std::lower_bound(std::begin(blocks_), std::end(blocks_), key, CompareCacheBlockByKey{});
|
auto iter = std::lower_bound(std::begin(blocks_), std::end(blocks_), key, CompareCacheBlockByKey{});
|
||||||
|
|
|
@ -26,6 +26,44 @@ struct tr_torrent;
|
||||||
class Cache
|
class Cache
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
class BlockData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BlockData(size_t size)
|
||||||
|
: size_{ size }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr auto size() const noexcept
|
||||||
|
{
|
||||||
|
return size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr auto* data() noexcept
|
||||||
|
{
|
||||||
|
return std::data(data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr const auto* data() const noexcept
|
||||||
|
{
|
||||||
|
return std::data(data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr auto* begin() const noexcept
|
||||||
|
{
|
||||||
|
return data();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr auto* end() const noexcept
|
||||||
|
{
|
||||||
|
return begin() + size();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::array<uint8_t, tr_block_info::BlockSize> data_;
|
||||||
|
size_t const size_;
|
||||||
|
};
|
||||||
|
|
||||||
Cache(tr_torrents& torrents, int64_t max_bytes);
|
Cache(tr_torrents& torrents, int64_t max_bytes);
|
||||||
|
|
||||||
int set_limit(int64_t new_limit);
|
int set_limit(int64_t new_limit);
|
||||||
|
@ -36,7 +74,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// @return any error code from cacheTrim()
|
// @return any error code from cacheTrim()
|
||||||
int write_block(tr_torrent_id_t tor, tr_block_index_t block, std::unique_ptr<std::vector<uint8_t>> writeme);
|
int write_block(tr_torrent_id_t tor, tr_block_index_t block, std::unique_ptr<BlockData> writeme);
|
||||||
|
|
||||||
int read_block(tr_torrent* torrent, tr_block_info::Location const& loc, uint32_t len, uint8_t* setme);
|
int read_block(tr_torrent* torrent, tr_block_info::Location const& loc, uint32_t len, uint8_t* setme);
|
||||||
int prefetch_block(tr_torrent* torrent, tr_block_info::Location const& loc, uint32_t len);
|
int prefetch_block(tr_torrent* torrent, tr_block_info::Location const& loc, uint32_t len);
|
||||||
|
@ -49,7 +87,7 @@ private:
|
||||||
struct CacheBlock
|
struct CacheBlock
|
||||||
{
|
{
|
||||||
Key key;
|
Key key;
|
||||||
std::unique_ptr<std::vector<uint8_t>> buf;
|
std::unique_ptr<BlockData> buf;
|
||||||
time_t time_added = {};
|
time_t time_added = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -224,7 +224,7 @@ struct tr_incoming
|
||||||
struct incoming_piece_data
|
struct incoming_piece_data
|
||||||
{
|
{
|
||||||
explicit incoming_piece_data(uint32_t block_size)
|
explicit incoming_piece_data(uint32_t block_size)
|
||||||
: buf{ std::make_unique<std::vector<uint8_t>>(block_size) }
|
: buf{ std::make_unique<Cache::BlockData>(block_size) }
|
||||||
, block_size_{ block_size }
|
, block_size_{ block_size }
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -249,7 +249,7 @@ struct tr_incoming
|
||||||
return have_.count() >= block_size_;
|
return have_.count() >= block_size_;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<std::vector<uint8_t>> buf;
|
std::unique_ptr<Cache::BlockData> buf;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::bitset<tr_block_info::BlockSize> have_;
|
std::bitset<tr_block_info::BlockSize> have_;
|
||||||
|
@ -1347,7 +1347,7 @@ void peerMadeRequest(tr_peerMsgsImpl* msgs, struct peer_request const* req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int clientGotBlock(tr_peerMsgsImpl* msgs, std::unique_ptr<std::vector<uint8_t>> block_data, tr_block_index_t block);
|
int clientGotBlock(tr_peerMsgsImpl* msgs, std::unique_ptr<Cache::BlockData> block_data, tr_block_index_t block);
|
||||||
|
|
||||||
ReadResult read_piece_data(tr_peerMsgsImpl* msgs, PeerMessageReader& payload)
|
ReadResult read_piece_data(tr_peerMsgsImpl* msgs, PeerMessageReader& payload)
|
||||||
{
|
{
|
||||||
|
@ -1645,7 +1645,7 @@ ReadResult process_peer_message(tr_peerMsgsImpl* msgs, uint8_t id, PeerMessageRe
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns 0 on success, or an errno on failure */
|
/* returns 0 on success, or an errno on failure */
|
||||||
int clientGotBlock(tr_peerMsgsImpl* msgs, std::unique_ptr<std::vector<uint8_t>> block_data, tr_block_index_t const block)
|
int clientGotBlock(tr_peerMsgsImpl* msgs, std::unique_ptr<Cache::BlockData> block_data, tr_block_index_t const block)
|
||||||
{
|
{
|
||||||
TR_ASSERT(msgs != nullptr);
|
TR_ASSERT(msgs != nullptr);
|
||||||
|
|
||||||
|
|
|
@ -338,7 +338,7 @@ public:
|
||||||
tr_session* session,
|
tr_session* session,
|
||||||
tr_torrent_id_t tor_id,
|
tr_torrent_id_t tor_id,
|
||||||
tr_block_index_t block,
|
tr_block_index_t block,
|
||||||
std::unique_ptr<std::vector<uint8_t>>& data,
|
std::unique_ptr<Cache::BlockData> data,
|
||||||
tr_webseed* webseed)
|
tr_webseed* webseed)
|
||||||
: session_{ session }
|
: session_{ session }
|
||||||
, tor_id_{ tor_id }
|
, tor_id_{ tor_id }
|
||||||
|
@ -363,7 +363,7 @@ private:
|
||||||
tr_session* const session_;
|
tr_session* const session_;
|
||||||
tr_torrent_id_t const tor_id_;
|
tr_torrent_id_t const tor_id_;
|
||||||
tr_block_index_t const block_;
|
tr_block_index_t const block_;
|
||||||
std::unique_ptr<std::vector<uint8_t>> data_;
|
std::unique_ptr<Cache::BlockData> data_;
|
||||||
tr_webseed* const webseed_;
|
tr_webseed* const webseed_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -394,10 +394,9 @@ void useFetchedBlocks(tr_webseed_task* task)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto block_buf = std::make_unique<std::vector<uint8_t>>();
|
auto block_buf = std::make_unique<Cache::BlockData>(block_size);
|
||||||
block_buf->resize(block_size);
|
|
||||||
evbuffer_remove(task->content(), std::data(*block_buf), std::size(*block_buf));
|
evbuffer_remove(task->content(), std::data(*block_buf), std::size(*block_buf));
|
||||||
auto* const data = new write_block_data{ session, tor->id(), task->loc.block, block_buf, webseed };
|
auto* const data = new write_block_data{ session, tor->id(), task->loc.block, std::move(block_buf), webseed };
|
||||||
session->runInSessionThread(&write_block_data::write_block_func, data);
|
session->runInSessionThread(&write_block_data::write_block_func, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,7 @@ TEST_P(IncompleteDirTest, incompleteDir)
|
||||||
tr_torrent* tor = {};
|
tr_torrent* tor = {};
|
||||||
tr_block_index_t block = {};
|
tr_block_index_t block = {};
|
||||||
tr_piece_index_t pieceIndex = {};
|
tr_piece_index_t pieceIndex = {};
|
||||||
std::unique_ptr<std::vector<uint8_t>> buf = {};
|
std::unique_ptr<Cache::BlockData> buf = {};
|
||||||
bool done = {};
|
bool done = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -97,7 +97,8 @@ TEST_P(IncompleteDirTest, incompleteDir)
|
||||||
|
|
||||||
for (tr_block_index_t block_index = begin; block_index < end; ++block_index)
|
for (tr_block_index_t block_index = begin; block_index < end; ++block_index)
|
||||||
{
|
{
|
||||||
data.buf = std::make_unique<std::vector<uint8_t>>(tr_block_info::BlockSize, '\0');
|
data.buf = std::make_unique<Cache::BlockData>(tr_block_info::BlockSize);
|
||||||
|
std::fill_n(std::data(*data.buf), tr_block_info::BlockSize, '\0');
|
||||||
data.block = block_index;
|
data.block = block_index;
|
||||||
data.done = false;
|
data.done = false;
|
||||||
session_->runInSessionThread(test_incomplete_dir_threadfunc, &data);
|
session_->runInSessionThread(test_incomplete_dir_threadfunc, &data);
|
||||||
|
|
Loading…
Add table
Reference in a new issue