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
|
||||
{
|
||||
// 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.
|
||||
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));
|
||||
}
|
||||
TR_ASSERT(std::size(buf) == buflen);
|
||||
towrite = &buf;
|
||||
out = std::data(buf);
|
||||
outlen = std::size(buf);
|
||||
}
|
||||
|
||||
// save it
|
||||
|
@ -107,13 +109,13 @@ int Cache::write_contiguous(CIter const begin, CIter const end) const
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
++disk_writes_;
|
||||
disk_write_bytes_ += std::size(*towrite);
|
||||
disk_write_bytes_ += outlen;
|
||||
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 iter = std::lower_bound(std::begin(blocks_), std::end(blocks_), key, CompareCacheBlockByKey{});
|
||||
|
|
|
@ -26,6 +26,44 @@ struct tr_torrent;
|
|||
class Cache
|
||||
{
|
||||
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);
|
||||
|
||||
int set_limit(int64_t new_limit);
|
||||
|
@ -36,7 +74,7 @@ public:
|
|||
}
|
||||
|
||||
// @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 prefetch_block(tr_torrent* torrent, tr_block_info::Location const& loc, uint32_t len);
|
||||
|
@ -49,7 +87,7 @@ private:
|
|||
struct CacheBlock
|
||||
{
|
||||
Key key;
|
||||
std::unique_ptr<std::vector<uint8_t>> buf;
|
||||
std::unique_ptr<BlockData> buf;
|
||||
time_t time_added = {};
|
||||
};
|
||||
|
||||
|
|
|
@ -224,7 +224,7 @@ struct tr_incoming
|
|||
struct incoming_piece_data
|
||||
{
|
||||
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 }
|
||||
{
|
||||
}
|
||||
|
@ -249,7 +249,7 @@ struct tr_incoming
|
|||
return have_.count() >= block_size_;
|
||||
}
|
||||
|
||||
std::unique_ptr<std::vector<uint8_t>> buf;
|
||||
std::unique_ptr<Cache::BlockData> buf;
|
||||
|
||||
private:
|
||||
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)
|
||||
{
|
||||
|
@ -1645,7 +1645,7 @@ ReadResult process_peer_message(tr_peerMsgsImpl* msgs, uint8_t id, PeerMessageRe
|
|||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
|
|
|
@ -338,7 +338,7 @@ public:
|
|||
tr_session* session,
|
||||
tr_torrent_id_t tor_id,
|
||||
tr_block_index_t block,
|
||||
std::unique_ptr<std::vector<uint8_t>>& data,
|
||||
std::unique_ptr<Cache::BlockData> data,
|
||||
tr_webseed* webseed)
|
||||
: session_{ session }
|
||||
, tor_id_{ tor_id }
|
||||
|
@ -363,7 +363,7 @@ private:
|
|||
tr_session* const session_;
|
||||
tr_torrent_id_t const tor_id_;
|
||||
tr_block_index_t const block_;
|
||||
std::unique_ptr<std::vector<uint8_t>> data_;
|
||||
std::unique_ptr<Cache::BlockData> data_;
|
||||
tr_webseed* const webseed_;
|
||||
};
|
||||
|
||||
|
@ -394,10 +394,9 @@ void useFetchedBlocks(tr_webseed_task* task)
|
|||
}
|
||||
else
|
||||
{
|
||||
auto block_buf = std::make_unique<std::vector<uint8_t>>();
|
||||
block_buf->resize(block_size);
|
||||
auto block_buf = std::make_unique<Cache::BlockData>(block_size);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ TEST_P(IncompleteDirTest, incompleteDir)
|
|||
tr_torrent* tor = {};
|
||||
tr_block_index_t block = {};
|
||||
tr_piece_index_t pieceIndex = {};
|
||||
std::unique_ptr<std::vector<uint8_t>> buf = {};
|
||||
std::unique_ptr<Cache::BlockData> buf = {};
|
||||
bool done = {};
|
||||
};
|
||||
|
||||
|
@ -97,7 +97,8 @@ TEST_P(IncompleteDirTest, incompleteDir)
|
|||
|
||||
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.done = false;
|
||||
session_->runInSessionThread(test_incomplete_dir_threadfunc, &data);
|
||||
|
|
Loading…
Add table
Reference in a new issue